Feature/config from env (#1463)

* Clients use env

* Explorer api uses env

* Mainnet and qa env files

* Set CONFIGURED on the mainnet defaulting

* Gateway uses env

* Mixnode uses env

* Wallet error simplification

* Network requester takes only mainnet client address

* Validator api uses env

* Mixnet contract uses denom from instantiate

* Vesting contract uses denom from instantiate

* More contract test refactoring

* Coconut bandwidth contract uses denom from instantiate

* Bandwidth claim contract uses denom from instantiate and remove from Cargos

* More remove from Cargos and one missed DEFAULT_NETWORK

* Refactor some other missed places

* Minor fixes

* Test and clippy fixes

* Update CHANGELOG
This commit is contained in:
Bogdan-Ștefan Neacşu
2022-07-20 13:16:37 +03:00
committed by GitHub
parent c485934b06
commit 9ca3f69aa8
99 changed files with 900 additions and 617 deletions
+3
View File
@@ -52,6 +52,8 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- socks5 client/websocket client: upgrade to latest clap and switched to declarative commandline parsing.
- validator-api: fee payment for multisig operations comes from the gateway account instead of the validator APIs' accounts ([#1419])
- multisig-contract: Limit the proposal creating functionality to one address (coconut-bandwidth-contract address) ([#1457])
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
@@ -74,6 +76,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#1419]: https://github.com/nymtech/nym/pull/1419
[#1427]: https://github.com/nymtech/nym/pull/1427
[#1457]: https://github.com/nymtech/nym/pull/1457
[#1463]: https://github.com/nymtech/nym/pull/1463
## [nym-wallet-v1.0.7](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.7) (2022-07-11)
Generated
+2 -6
View File
@@ -928,7 +928,6 @@ dependencies = [
"coconut-interface",
"cosmrs",
"crypto",
"network-defaults",
"rand 0.7.3",
"thiserror",
"url",
@@ -1591,6 +1590,7 @@ name = "explorer-api"
version = "1.0.1"
dependencies = [
"chrono",
"clap 3.2.8",
"humantime-serde",
"isocountry",
"itertools",
@@ -2871,7 +2871,6 @@ dependencies = [
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
@@ -2968,6 +2967,7 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if 1.0.0",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -3065,7 +3065,6 @@ dependencies = [
"credentials",
"crypto",
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
@@ -3232,7 +3231,6 @@ dependencies = [
"credentials",
"crypto",
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
@@ -5390,7 +5388,6 @@ version = "1.0.1"
dependencies = [
"async-trait",
"log",
"network-defaults",
"reqwest",
"serde",
"serde_json",
@@ -6338,7 +6335,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
+1 -2
View File
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::*;
use config::NymConfig;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
@@ -366,7 +365,7 @@ impl<T: NymConfig> Default for Client<T> {
version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(),
disabled_credentials_mode: true,
validator_api_urls: default_api_endpoints(),
validator_api_urls: vec![],
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_encryption_key_file: Default::default(),
+9 -4
View File
@@ -4,7 +4,7 @@
use crate::error::Result;
use crate::{MNEMONIC, NYMD_URL};
use bip39::Mnemonic;
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use std::str::FromStr;
use url::Url;
use validator_client::nymd;
@@ -13,18 +13,23 @@ use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
pub(crate) struct Client {
nymd_client: NymdClient<SigningNymdClient>,
mix_denom_base: String,
}
impl Client {
pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
let network_details = NymNetworkDetails::new_from_env();
let config = nymd::Config::try_from_nym_network_details(&network_details)
.expect("failed to construct valid validator client config with the provided network");
let nymd_client =
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
Client { nymd_client }
Client {
nymd_client,
mix_denom_base: network_details.chain_details.mix_denom.base,
}
}
pub async fn deposit(
@@ -34,7 +39,7 @@ impl Client {
encryption_key: String,
fee: Option<Fee>,
) -> Result<String> {
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
let amount = Coin::new(amount as u128, self.mix_denom_base.clone());
Ok(self
.nymd_client
.deposit(
-1
View File
@@ -22,7 +22,6 @@ url = "2.2"
clap = { version = "3.2.8", features = ["cargo", "derive"] }
dirs = "4.0"
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
log = "0.4" # self explanatory
pretty_env_logger = "0.4" # for formatting log messages
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
+10 -4
View File
@@ -3,7 +3,6 @@
use crate::client::config::{Config, SocketType};
use clap::{Parser, Subcommand};
use network_defaults::DEFAULT_NETWORK;
use url::Url;
#[cfg(not(feature = "coconut"))]
@@ -28,7 +27,6 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -46,8 +44,6 @@ fn long_version() -> String {
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
)
}
@@ -58,6 +54,10 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: Commands,
}
@@ -113,6 +113,12 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
.expect("api validator not set");
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
}
if args.disable_socket {
+1 -10
View File
@@ -3,7 +3,7 @@
use crate::client::config::{Config, MISSING_VALUE};
use config::{defaults::default_api_endpoints, NymConfig};
use config::NymConfig;
use version_checker::Version;
use clap::Args;
@@ -105,15 +105,6 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
config
.get_base_mut()
.set_custom_validator_apis(default_api_endpoints());
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
+2 -1
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, Parser};
use network_defaults::setup_env;
pub mod client;
pub mod commands;
@@ -9,11 +10,11 @@ pub mod websocket;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
let args = commands::Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(&args).await;
}
-1
View File
@@ -13,7 +13,6 @@ path = "src/lib.rs"
[dependencies]
clap = { version = "3.2.8", features = ["cargo", "derive"] }
dirs = "4.0"
dotenv = "0.15.0"
futures = "0.3"
log = "0.4"
pin-project = "1.0"
+8 -4
View File
@@ -3,7 +3,6 @@
use crate::client::config::Config;
use clap::{Parser, Subcommand};
use network_defaults::DEFAULT_NETWORK;
use url::Url;
pub mod init;
@@ -28,7 +27,6 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -46,8 +44,6 @@ fn long_version() -> String {
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
)
}
@@ -58,6 +54,10 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: Commands,
}
@@ -112,6 +112,10 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
}
if let Some(port) = args.port {
+1 -10
View File
@@ -3,7 +3,7 @@
use crate::client::config::{Config, MISSING_VALUE};
use config::{defaults::default_api_endpoints, NymConfig};
use config::NymConfig;
use version_checker::Version;
use clap::Args;
@@ -104,15 +104,6 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
config
.get_base_mut()
.set_custom_validator_apis(default_api_endpoints());
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
+2 -1
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, Parser};
use network_defaults::setup_env;
pub mod client;
mod commands;
@@ -9,11 +10,11 @@ pub mod socks;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
let args = commands::Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(&args).await;
}
@@ -28,7 +28,7 @@ use mixnet_contract_common::{
RewardedSetUpdateDetails,
};
#[cfg(feature = "nymd-client")]
use network_defaults::{all::Network, NymNetworkDetails};
use network_defaults::NymNetworkDetails;
#[cfg(feature = "nymd-client")]
use std::collections::{HashMap, HashSet};
@@ -113,9 +113,6 @@ impl Config {
#[cfg(feature = "nymd-client")]
pub struct Client<C> {
// compatibility : (
pub network: Network,
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
// non-trivial amount of work and it's out of scope of the current branch
mnemonic: Option<bip39::Mnemonic>,
@@ -134,9 +131,6 @@ pub struct Client<C> {
impl Client<SigningNymdClient> {
pub fn new_signing(
config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
mnemonic: bip39::Mnemonic,
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
@@ -148,7 +142,6 @@ impl Client<SigningNymdClient> {
)?;
Ok(Client {
network,
mnemonic: Some(mnemonic),
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -176,18 +169,12 @@ impl Client<SigningNymdClient> {
#[cfg(feature = "nymd-client")]
impl Client<QueryNymdClient> {
pub fn new_query(
config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client =
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
Ok(Client {
network,
mnemonic: None,
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -12,7 +12,6 @@ use multisig_contract_common::msg::ExecuteMsg;
use async_trait::async_trait;
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
use cw3::Vote;
use network_defaults::DEFAULT_NETWORK;
#[async_trait]
pub trait MultisigSigningClient {
@@ -49,7 +48,10 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
funds: Coin::new(
voucher_value,
self.config.chain_details.mix_denom.base.clone(),
),
};
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
@@ -207,35 +207,20 @@ mod tests {
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
];
let prefixes = vec![
MAINNET.bech32_prefix(),
SANDBOX.bech32_prefix(),
QA.bech32_prefix(),
];
let prefix = MAINNET.bech32_prefix();
for prefix in prefixes {
let addrs = match prefix.as_ref() {
"nymt" => vec![
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
],
"n" => vec![
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
],
_ => panic!("Test needs to be updated with new bech32 prefix"),
};
for (idx, mnemonic) in mnemonics.iter().enumerate() {
let wallet =
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
.unwrap();
assert_eq!(
wallet.try_derive_accounts().unwrap()[0].address,
addrs[idx].parse().unwrap()
)
}
let addrs = vec![
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
];
for (idx, mnemonic) in mnemonics.iter().enumerate() {
let wallet =
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap()).unwrap();
assert_eq!(
wallet.try_derive_accounts().unwrap()[0].address,
addrs[idx].parse().unwrap()
)
}
}
}
@@ -11,6 +11,7 @@ use crate::{deposit::DepositData, spend_credential::SpendCredentialData};
pub struct InstantiateMsg {
pub multisig_addr: String,
pub pool_addr: String,
pub mix_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -14,7 +14,6 @@ serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
thiserror = "1.0"
network-defaults = { path = "../../network-defaults" }
fixed = { version = "1.1", features = ["serde"] }
az = "1.1"
log = "0.4.14"
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantiateMsg {
pub rewarding_validator_address: String,
pub mixnet_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
@@ -14,6 +14,7 @@ use cw_utils::{Duration, Expiration, Threshold};
pub struct InstantiateMsg {
// this is the group contract that contains the member list
pub group_addr: String,
pub coconut_bandwidth_contract_address: String,
pub threshold: Threshold,
pub max_voting_period: Duration,
}
@@ -1,6 +1,5 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::MIX_DENOM;
use cosmwasm_std::{Coin, Timestamp};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -10,8 +9,8 @@ pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
pub mod events;
pub mod messages;
pub fn one_ucoin() -> Coin {
Coin::new(1, MIX_DENOM.base)
pub fn one_ucoin(denom: String) -> Coin {
Coin::new(1, denom)
}
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
@@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
#[serde(rename_all = "snake_case")]
pub struct InitMsg {
pub mixnet_contract_address: String,
pub mix_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
-1
View File
@@ -14,7 +14,6 @@ url = "2.2"
# I guess temporarily until we get serde support in coconut up and running
coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
network-defaults = { path = "../network-defaults" }
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
validator-client = { path = "../client-libs/validator-client" }
+11 -7
View File
@@ -1,4 +1,3 @@
use config::defaults::DEFAULT_NETWORK;
use subtle_encoding::bech32;
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -15,16 +14,15 @@ pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
}
}
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
pub fn validate_bech32_prefix(bech32_prefix: &str, address: &str) -> Result<(), Bech32Error> {
let prefix = try_bech32_decode(address)?;
if prefix == DEFAULT_NETWORK.bech32_prefix() {
if prefix == bech32_prefix {
Ok(())
} else {
Err(Bech32Error::WrongPrefix(format!(
"your bech32 address prefix should be {}, not {}",
DEFAULT_NETWORK.bech32_prefix(),
prefix
bech32_prefix, prefix
)))
}
}
@@ -33,6 +31,8 @@ pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
mod tests {
use super::*;
const TEST_BECH32_PREFIX: &str = "n";
mod decoding_bech32_addresses {
use super::*;
@@ -71,9 +71,12 @@ mod tests {
assert_eq!(
Err(Bech32Error::WrongPrefix(format!(
"your bech32 address prefix should be {}, not punk",
DEFAULT_NETWORK.bech32_prefix()
TEST_BECH32_PREFIX
))),
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
validate_bech32_prefix(
TEST_BECH32_PREFIX,
"punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0"
)
)
}
@@ -82,6 +85,7 @@ mod tests {
assert_eq!(
Ok(()),
validate_bech32_prefix(
TEST_BECH32_PREFIX,
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"
)
)
+1
View File
@@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
cfg-if = "1.0.0"
dotenv = "0.15.0"
hex-literal = "0.3.3"
once_cell = "1.7.2"
serde = {version = "1.0", features = ["derive"]}
-11
View File
@@ -1,11 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
fn main() {
match option_env!("NETWORK") {
None | Some("mainnet") => println!("cargo:rustc-cfg=network=\"mainnet\"",),
Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
_ => panic!("No such network"),
}
}
+63 -61
View File
@@ -3,6 +3,7 @@
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::{env::var, path::PathBuf};
use url::Url;
pub mod all;
@@ -10,36 +11,10 @@ pub mod eth_contract;
pub mod mainnet;
pub mod qa;
pub mod sandbox;
pub mod var_names;
// The set of defaults that are decided at compile time. Ideally we want to reduce these to a
// minimum.
// Keep DENOM around mostly for use in contracts. (TODO: consider moving it there, or renaming?)
cfg_if::cfg_if! {
if #[cfg(network = "mainnet")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
pub const MIX_DENOM: DenomDetails = mainnet::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = mainnet::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "qa")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
pub const MIX_DENOM: DenomDetails = qa::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = qa::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "sandbox")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
pub const MIX_DENOM: DenomDetails = sandbox::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = sandbox::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
}
}
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainDetails {
@@ -82,23 +57,56 @@ impl NymNetworkDetails {
NymNetworkDetails::default()
}
pub fn new_qa() -> Self {
(&*QA_DEFAULTS).into()
}
pub fn new_sandbox() -> Self {
(&*SANDBOX_DEFAULTS).into()
pub fn new_from_env() -> Self {
NymNetworkDetails::new()
.with_bech32_account_prefix(
var(var_names::BECH32_PREFIX).expect("bech32 prefix not set"),
)
.with_mix_denom(DenomDetailsOwned {
base: var(var_names::MIX_DENOM).expect("mix denomination base not set"),
display: var(var_names::MIX_DENOM_DISPLAY)
.expect("mix denomination display not set"),
display_exponent: var(var_names::DENOMS_EXPONENT)
.expect("denomination exponent not set")
.parse()
.expect("denomination exponent is not u32"),
})
.with_stake_denom(DenomDetailsOwned {
base: var(var_names::STAKE_DENOM).expect("stake denomination base not set"),
display: var(var_names::STAKE_DENOM_DISPLAY)
.expect("stake denomination display not set"),
display_exponent: var(var_names::DENOMS_EXPONENT)
.expect("denomination exponent not set")
.parse()
.expect("denomination exponent is not u32"),
})
.with_validator_endpoint(ValidatorDetails::new(
var(var_names::NYMD_VALIDATOR).expect("nymd validator not set"),
Some(var(var_names::API_VALIDATOR).expect("api validator not set")),
))
.with_mixnet_contract(Some(
var(var_names::MIXNET_CONTRACT_ADDRESS).expect("mixnet contract not set"),
))
.with_vesting_contract(Some(
var(var_names::VESTING_CONTRACT_ADDRESS).expect("vesting contract not set"),
))
.with_bandwidth_claim_contract(Some(
var(var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS)
.expect("bandwidth claim contract not set"),
))
.with_coconut_bandwidth_contract(Some(
var(var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS)
.expect("coconut bandwidth contract not set"),
))
.with_multisig_contract(Some(
var(var_names::MULTISIG_CONTRACT_ADDRESS).expect("multisig contract not set"),
))
}
pub fn new_mainnet() -> Self {
(&*MAINNET_DEFAULTS).into()
}
pub fn current_default() -> Self {
// backwards compatibility reasons
DEFAULT_NETWORK.details()
}
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
self.chain_details.bech32_account_prefix = prefix.into();
self
@@ -333,27 +341,21 @@ impl ValidatorDetails {
}
}
pub fn default_statistics_service_url() -> Url {
DEFAULT_NETWORK
.statistics_service_url()
.parse()
.expect("the provided statistics service url is invalid!")
}
pub fn default_nymd_endpoints() -> Vec<Url> {
DEFAULT_NETWORK
.validators()
.iter()
.map(ValidatorDetails::nymd_url)
.collect()
}
pub fn default_api_endpoints() -> Vec<Url> {
DEFAULT_NETWORK
.validators()
.iter()
.filter_map(ValidatorDetails::api_url)
.collect()
pub fn setup_env(config_env_file: Option<PathBuf>) {
match std::env::var(var_names::CONFIGURED) {
// if the configuration is not already set in the env vars
Err(std::env::VarError::NotPresent) => {
if let Some(config_env_file) = config_env_file {
dotenv::from_path(config_env_file)
.expect("Invalid path to environment configuration file");
} else {
// if nothing is set, the use mainnet defaults
crate::mainnet::export_to_env();
}
}
Err(_) => crate::mainnet::export_to_env(),
_ => {}
}
}
// Name of the event triggered by the eth contract. If the event name is changed,
+44 -4
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::var_names;
use crate::{DenomDetails, ValidatorDetails};
pub(crate) const BECH32_PREFIX: &str = "n";
@@ -24,9 +25,48 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090";
pub const NYMD_VALIDATOR: &str = "https://rpc.nyx.nodes.guru/";
pub const API_VALIDATOR: &str = "https://validator.nymtech.net/api/";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://rpc.nyx.nodes.guru/",
Some("https://validator.nymtech.net/api/"),
)]
vec![ValidatorDetails::new(NYMD_VALIDATOR, Some(API_VALIDATOR))]
}
pub fn export_to_env() {
std::env::set_var(var_names::CONFIGURED, "true");
std::env::set_var(var_names::BECH32_PREFIX, BECH32_PREFIX);
std::env::set_var(var_names::MIX_DENOM, MIX_DENOM.base);
std::env::set_var(var_names::MIX_DENOM_DISPLAY, MIX_DENOM.display);
std::env::set_var(var_names::STAKE_DENOM, STAKE_DENOM.base);
std::env::set_var(var_names::STAKE_DENOM_DISPLAY, STAKE_DENOM.display);
std::env::set_var(
var_names::DENOMS_EXPONENT,
STAKE_DENOM.display_exponent.to_string(),
);
std::env::set_var(var_names::MIXNET_CONTRACT_ADDRESS, MIXNET_CONTRACT_ADDRESS);
std::env::set_var(
var_names::VESTING_CONTRACT_ADDRESS,
VESTING_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::MULTISIG_CONTRACT_ADDRESS,
MULTISIG_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
);
std::env::set_var(
var_names::STATISTICS_SERVICE_DOMAIN_ADDRESS,
STATISTICS_SERVICE_DOMAIN_ADDRESS,
);
std::env::set_var(var_names::NYMD_VALIDATOR, NYMD_VALIDATOR);
std::env::set_var(var_names::API_VALIDATOR, API_VALIDATOR);
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// Environment variable that, if set, shows the environment is currently configured
pub const CONFIGURED: &str = "CONFIGURED";
pub const BECH32_PREFIX: &str = "BECH32_PREFIX";
pub const MIX_DENOM: &str = "MIX_DENOM";
pub const MIX_DENOM_DISPLAY: &str = "MIX_DENOM_DISPLAY";
pub const STAKE_DENOM: &str = "STAKE_DENOM";
pub const STAKE_DENOM_DISPLAY: &str = "STAKE_DENOM_DISPLAY";
pub const DENOMS_EXPONENT: &str = "DENOMS_EXPONENT";
pub const MIXNET_CONTRACT_ADDRESS: &str = "MIXNET_CONTRACT_ADDRESS";
pub const VESTING_CONTRACT_ADDRESS: &str = "VESTING_CONTRACT_ADDRESS";
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "BANDWIDTH_CLAIM_CONTRACT_ADDRESS";
pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT_ADDRESS";
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "STATISTICS_SERVICE_DOMAIN_ADDRESS";
pub const NYMD_VALIDATOR: &str = "NYMD_VALIDATOR";
pub const API_VALIDATOR: &str = "API_VALIDATOR";
-2
View File
@@ -17,5 +17,3 @@ serde_json = "1"
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
thiserror = "1"
tokio = { version = "1.19.1", features = [ "time" ] }
network-defaults = { path = "../network-defaults" }
+7 -6
View File
@@ -50,7 +50,6 @@ name = "bandwidth-claim"
version = "1.0.0"
dependencies = [
"bandwidth-claim-contract",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"schemars",
@@ -221,7 +220,6 @@ version = "0.1.0"
dependencies = [
"bandwidth-claim-contract",
"coconut-bandwidth-contract-common",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"cw-controllers",
@@ -249,7 +247,6 @@ dependencies = [
"bandwidth-claim-contract",
"coconut-bandwidth",
"coconut-bandwidth-contract-common",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"cw-controllers",
@@ -544,7 +541,6 @@ dependencies = [
"cw4",
"cw4-group",
"multisig-contract-common",
"network-defaults",
"schemars",
"serde",
"thiserror",
@@ -616,6 +612,12 @@ dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dyn-clone"
version = "1.0.4"
@@ -1080,7 +1082,6 @@ dependencies = [
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
@@ -1106,6 +1107,7 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -1852,7 +1854,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
-2
View File
@@ -9,8 +9,6 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dev-dependencies]
config = { path = "../../common/config"}
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
+4 -3
View File
@@ -62,10 +62,11 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
pub mod tests {
use super::*;
use bandwidth_claim_contract::payment::PagedPaymentResponse;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
const TEST_MIX_DENOM: &str = "unym";
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies();
@@ -91,11 +92,11 @@ pub mod tests {
// Contract balance should match what we initialized it as
assert_eq!(
coins(0, MIX_DENOM.base),
coins(0, TEST_MIX_DENOM),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, MIX_DENOM.base)
.query_balance(env.contract.address, TEST_MIX_DENOM)
.unwrap()]
);
}
-1
View File
@@ -12,7 +12,6 @@ crate-type = ["cdylib", "rlib"]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
config = { path = "../../common/config"}
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
+6 -3
View File
@@ -25,12 +25,14 @@ pub fn instantiate(
) -> Result<Response, ContractError> {
let multisig_addr = deps.api.addr_validate(&msg.multisig_addr)?;
let pool_addr = deps.api.addr_validate(&msg.pool_addr)?;
let mix_denom = msg.mix_denom;
ADMIN.set(deps.branch(), Some(multisig_addr.clone()))?;
let cfg = Config {
multisig_addr,
pool_addr,
mix_denom,
};
CONFIG.save(deps.storage, &cfg)?;
@@ -74,8 +76,8 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::fixtures::TEST_MIX_DENOM;
use crate::support::tests::helpers::*;
use config::defaults::MIX_DENOM;
use cosmwasm_std::coins;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
@@ -86,6 +88,7 @@ mod tests {
let msg = InstantiateMsg {
multisig_addr: String::from(MULTISIG_CONTRACT),
pool_addr: String::from(POOL_CONTRACT),
mix_denom: TEST_MIX_DENOM.to_string(),
};
let info = mock_info("creator", &[]);
@@ -94,11 +97,11 @@ mod tests {
// Contract balance should be 0
assert_eq!(
coins(0, MIX_DENOM.base),
coins(0, TEST_MIX_DENOM),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, MIX_DENOM.base)
.query_balance(env.contract.address, TEST_MIX_DENOM)
.unwrap()]
);
}
+2 -4
View File
@@ -5,8 +5,6 @@ use cosmwasm_std::StdError;
use cw_controllers::AdminError;
use thiserror::Error;
use config::defaults::MIX_DENOM;
/// Custom errors for contract failure conditions.
///
/// Add any other custom errors you like here.
@@ -22,8 +20,8 @@ pub enum ContractError {
#[error("No coin was sent for voucher")]
NoCoin,
#[error("Wrong coin denomination, you must send {}", MIX_DENOM.base)]
WrongDenom,
#[error("Wrong coin denomination, you must send {mix_denom}")]
WrongDenom { mix_denom: String },
#[error("There aren't enough funds in the contract")]
NotEnoughFunds,
+1
View File
@@ -13,6 +13,7 @@ pub const ADMIN: Admin = Admin::new("admin");
pub struct Config {
pub multisig_addr: Addr,
pub pool_addr: Addr,
pub mix_denom: String,
}
pub const CONFIG: Item<Config> = Item::new("config");
+2 -2
View File
@@ -43,8 +43,8 @@ mod tests {
use super::super::storage;
use crate::storage::SpendCredential;
use crate::support::tests::fixtures;
use crate::support::tests::fixtures::TEST_MIX_DENOM;
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialStatus;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::MockStorage;
use cosmwasm_std::Addr;
use cosmwasm_std::Coin;
@@ -76,7 +76,7 @@ mod tests {
#[test]
fn mark_as_spent_credential() {
let mut mock_storage = MockStorage::new();
let funds = Coin::new(100, MIX_DENOM.base);
let funds = Coin::new(100, TEST_MIX_DENOM);
let blind_serial_number = "blind_serial_number";
let gateway_cosmos_address: Addr = Addr::unchecked("gateway_cosmos_address");
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
use coconut_bandwidth_contract_common::spend_credential::{SpendCredential, SpendCredentialData};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{Addr, Coin};
pub const TEST_MIX_DENOM: &str = "unym";
pub fn spend_credential_fixture(blinded_serial_number: &str) -> SpendCredential {
SpendCredential::new(
Coin::new(100, MIX_DENOM.base),
Coin::new(100, TEST_MIX_DENOM),
blinded_serial_number.to_string(),
Addr::unchecked("gateway_owner_addr"),
)
@@ -15,7 +16,7 @@ pub fn spend_credential_fixture(blinded_serial_number: &str) -> SpendCredential
pub fn spend_credential_data_fixture(blinded_serial_number: &str) -> SpendCredentialData {
SpendCredentialData::new(
Coin::new(100, MIX_DENOM.base),
Coin::new(100, TEST_MIX_DENOM),
blinded_serial_number.to_string(),
"gateway_owner_addr".to_string(),
)
@@ -9,11 +9,14 @@ use coconut_bandwidth_contract_common::msg::InstantiateMsg;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
use cosmwasm_std::{Empty, MemoryStorage, OwnedDeps};
use super::fixtures::TEST_MIX_DENOM;
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
multisig_addr: String::from(MULTISIG_CONTRACT),
pool_addr: String::from(POOL_CONTRACT),
mix_denom: TEST_MIX_DENOM.to_string(),
};
let env = mock_env();
let info = mock_info("creator", &[]);
+34 -17
View File
@@ -15,10 +15,9 @@ use coconut_bandwidth_contract_common::events::{
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO,
DEPOSIT_VALUE,
};
use config::defaults::MIX_DENOM;
pub(crate) fn deposit_funds(
_deps: DepsMut<'_>,
deps: DepsMut<'_>,
_env: Env,
info: MessageInfo,
data: DepositData,
@@ -29,8 +28,9 @@ pub(crate) fn deposit_funds(
if info.funds.len() > 1 {
return Err(ContractError::MultipleDenoms);
}
if info.funds[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom);
let mix_denom = CONFIG.load(deps.storage)?.mix_denom;
if info.funds[0].denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
let voucher_value = info.funds.last().unwrap();
@@ -49,8 +49,9 @@ pub(crate) fn spend_credential(
_info: MessageInfo,
data: SpendCredentialData,
) -> Result<Response, ContractError> {
if data.funds().denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom);
let mix_denom = CONFIG.load(deps.storage)?.mix_denom;
if data.funds().denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
if storage::spent_credentials().has(deps.storage, data.blinded_serial_number()) {
return Err(ContractError::DuplicateBlindedSerialNumber);
@@ -84,12 +85,13 @@ pub(crate) fn release_funds(
info: MessageInfo,
funds: Coin,
) -> Result<Response, ContractError> {
if funds.denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom);
let mix_denom = CONFIG.load(deps.storage)?.mix_denom;
if funds.denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
let current_balance = deps
.querier
.query_balance(env.contract.address, MIX_DENOM.base)?;
.query_balance(env.contract.address, mix_denom)?;
if funds.amount > current_balance.amount {
return Err(ContractError::NotEnoughFunds);
}
@@ -133,7 +135,7 @@ mod tests {
Err(ContractError::NoCoin)
);
let coin = Coin::new(1000000, MIX_DENOM.base);
let coin = Coin::new(1000000, crate::support::tests::fixtures::TEST_MIX_DENOM);
let second_coin = Coin::new(1000000, "some_denom");
let info = mock_info("requester", &[coin, second_coin.clone()]);
@@ -145,7 +147,9 @@ mod tests {
let info = mock_info("requester", &[second_coin]);
assert_eq!(
deposit_funds(deps.as_mut(), env, info, data),
Err(ContractError::WrongDenom)
Err(ContractError::WrongDenom {
mix_denom: crate::support::tests::fixtures::TEST_MIX_DENOM.to_string()
})
);
}
@@ -163,7 +167,10 @@ mod tests {
verification_key.clone(),
encryption_key.clone(),
);
let coin = Coin::new(deposit_value, MIX_DENOM.base);
let coin = Coin::new(
deposit_value,
crate::support::tests::fixtures::TEST_MIX_DENOM,
);
let info = mock_info("requester", &[coin]);
let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap();
@@ -212,7 +219,7 @@ mod tests {
let mut deps = helpers::init_contract();
let env = mock_env();
let invalid_admin = "invalid admin";
let funds = Coin::new(1, MIX_DENOM.base);
let funds = Coin::new(1, crate::support::tests::fixtures::TEST_MIX_DENOM);
let err = release_funds(
deps.as_mut(),
@@ -221,7 +228,12 @@ mod tests {
Coin::new(1, "invalid denom"),
)
.unwrap_err();
assert_eq!(err, ContractError::WrongDenom);
assert_eq!(
err,
ContractError::WrongDenom {
mix_denom: crate::support::tests::fixtures::TEST_MIX_DENOM.to_string()
}
);
let err = release_funds(
deps.as_mut(),
@@ -248,7 +260,7 @@ mod tests {
fn valid_release() {
let mut deps = helpers::init_contract();
let env = mock_env();
let coin = Coin::new(1, MIX_DENOM.base);
let coin = Coin::new(1, crate::support::tests::fixtures::TEST_MIX_DENOM);
deps.querier
.update_balance(env.contract.address.clone(), vec![coin.clone()]);
@@ -327,10 +339,15 @@ mod tests {
String::new(),
);
let ret = spend_credential(deps.as_mut(), env.clone(), info.clone(), invalid_data);
assert_eq!(ret.unwrap_err(), ContractError::WrongDenom);
assert_eq!(
ret.unwrap_err(),
ContractError::WrongDenom {
mix_denom: crate::support::tests::fixtures::TEST_MIX_DENOM.to_string()
}
);
let invalid_data = SpendCredentialData::new(
Coin::new(1, MIX_DENOM.base),
Coin::new(1, crate::support::tests::fixtures::TEST_MIX_DENOM),
String::new(),
"Blinded Serial Number".to_string(),
);
-1
View File
@@ -9,7 +9,6 @@ edition = "2021"
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
config = { path = "../../common/config"}
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
@@ -7,16 +7,17 @@ use coconut_bandwidth_contract_common::{
deposit::DepositData,
msg::{ExecuteMsg, InstantiateMsg},
};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{coins, Addr};
use cw_controllers::AdminError;
use cw_multi_test::Executor;
const TEST_MIX_DENOM: &str = "unym";
#[test]
fn deposit_and_release() {
let init_funds = coins(10, MIX_DENOM.base);
let deposit_funds = coins(1, MIX_DENOM.base);
let release_funds = coins(2, MIX_DENOM.base);
let init_funds = coins(10, TEST_MIX_DENOM);
let deposit_funds = coins(1, TEST_MIX_DENOM);
let release_funds = coins(2, TEST_MIX_DENOM);
let mut app = mock_app(&init_funds);
let multisig_addr = String::from(MULTISIG_CONTRACT);
let pool_addr = String::from(POOL_CONTRACT);
@@ -26,6 +27,7 @@ fn deposit_and_release() {
let msg = InstantiateMsg {
multisig_addr: multisig_addr.clone(),
pool_addr: pool_addr.clone(),
mix_denom: TEST_MIX_DENOM.to_string(),
};
let contract_addr = app
.instantiate_contract(
@@ -94,6 +96,6 @@ fn deposit_and_release() {
&[],
)
.unwrap();
let pool_bal = app.wrap().query_balance(pool_addr, MIX_DENOM.base).unwrap();
let pool_bal = app.wrap().query_balance(pool_addr, TEST_MIX_DENOM).unwrap();
assert_eq!(pool_bal, deposit_funds[0]);
}
@@ -6,16 +6,19 @@ use coconut_bandwidth_contract_common::{
},
spend_credential::SpendCredentialData,
};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{coins, Addr, Coin, Decimal};
use cw4_group::msg::InstantiateMsg as GroupInstantiateMsg;
use cw_multi_test::Executor;
use cw_utils::{Duration, Threshold};
use multisig_contract_common::msg::InstantiateMsg as MultisigInstantiateMsg;
pub const TEST_COIN_DENOM: &str = "unym";
pub const TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
#[test]
fn spend_credential_creates_proposal() {
let init_funds = coins(10, MIX_DENOM.base);
let init_funds = coins(10, TEST_COIN_DENOM);
let mut app = mock_app(&init_funds);
let pool_addr = String::from(POOL_CONTRACT);
@@ -42,6 +45,7 @@ fn spend_credential_creates_proposal() {
percentage: Decimal::from_ratio(2u128, 3u128),
},
max_voting_period: Duration::Height(1000),
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
};
let multisig_contract_addr = app
.instantiate_contract(
@@ -58,6 +62,7 @@ fn spend_credential_creates_proposal() {
let msg = CoconutBandwidthInstantiateMsg {
multisig_addr: multisig_contract_addr.to_string(),
pool_addr,
mix_denom: TEST_COIN_DENOM.to_string(),
};
let coconut_bandwidth_contract_addr = app
.instantiate_contract(
@@ -83,7 +88,7 @@ fn spend_credential_creates_proposal() {
let msg = CoconutBandwidthExecuteMsg::SpendCredential {
data: SpendCredentialData::new(
Coin::new(1, MIX_DENOM.base),
Coin::new(1, TEST_COIN_DENOM),
String::from("blinded_serial_number"),
String::from("gateway_cosmos_address"),
),
@@ -126,7 +131,7 @@ fn spend_credential_creates_proposal() {
let msg = CoconutBandwidthExecuteMsg::SpendCredential {
data: SpendCredentialData::new(
Coin::new(1, MIX_DENOM.base),
Coin::new(1, TEST_COIN_DENOM),
String::from("blinded_serial_number2"),
String::from("gateway_cosmos_address"),
),
+11 -5
View File
@@ -61,9 +61,14 @@ pub fn debug_with_visibility<S: Into<String>>(api: &dyn Api, msg: S) {
api.debug(&*format!("\n\n\n=========================================\n{}\n=========================================\n\n\n", msg.into()));
}
fn default_initial_state(owner: Addr, rewarding_validator_address: Addr) -> ContractState {
fn default_initial_state(
owner: Addr,
mix_denom: String,
rewarding_validator_address: Addr,
) -> ContractState {
ContractState {
owner,
mix_denom,
rewarding_validator_address,
params: ContractStateParams {
minimum_mixnode_pledge: INITIAL_MIXNODE_PLEDGE,
@@ -88,7 +93,7 @@ pub fn instantiate(
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
let rewarding_validator_address = deps.api.addr_validate(&msg.rewarding_validator_address)?;
let state = default_initial_state(info.sender, rewarding_validator_address);
let state = default_initial_state(info.sender, msg.mixnet_denom, rewarding_validator_address);
init_epoch(deps.storage, env)?;
mixnet_params_storage::CONTRACT_STATE.save(deps.storage, &state)?;
@@ -452,7 +457,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
pub mod tests {
use super::*;
use crate::support::tests;
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
use crate::support::tests::fixtures::{TEST_COIN_DENOM, TEST_REWARDING_VALIDATOR_ADDRESS};
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
use mixnet_contract_common::PagedMixnodeResponse;
@@ -462,7 +467,8 @@ pub mod tests {
let mut deps = mock_dependencies();
let env = mock_env();
let msg = InstantiateMsg {
rewarding_validator_address: DEFAULT_NETWORK.rewarding_validator_address().to_string(),
rewarding_validator_address: TEST_REWARDING_VALIDATOR_ADDRESS.to_string(),
mixnet_denom: TEST_COIN_DENOM.to_string(),
};
let info = mock_info("creator", &[]);
@@ -484,7 +490,7 @@ pub mod tests {
// Contract balance should match what we initialized it as
assert_eq!(
coins(0, MIX_DENOM.base),
coins(0, TEST_COIN_DENOM),
tests::queries::query_contract_balance(env.contract.address, deps)
);
}
+4 -5
View File
@@ -199,8 +199,7 @@ pub(crate) fn query_mixnode_delegations_paged(
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::support::tests::test_helpers;
use config::defaults::MIX_DENOM;
use crate::support::tests::{fixtures::TEST_COIN_DENOM, test_helpers};
use cosmwasm_std::{coin, Addr, Storage};
use rand::Rng;
@@ -385,7 +384,7 @@ pub(crate) mod tests {
let delegation = Delegation::new(
delegation_owner.clone(),
node_identity.clone(),
coin(1234, MIX_DENOM.base),
coin(1234, TEST_COIN_DENOM),
1234,
None,
);
@@ -433,7 +432,7 @@ pub(crate) mod tests {
let delegation = Delegation::new(
delegation_owner2,
node_identity1.clone(),
coin(1234, MIX_DENOM.base),
coin(1234, TEST_COIN_DENOM),
1234,
None,
);
@@ -460,7 +459,7 @@ pub(crate) mod tests {
let delegation = Delegation::new(
delegation_owner1.clone(),
node_identity2,
coin(1234, MIX_DENOM.base),
coin(1234, TEST_COIN_DENOM),
1234,
None,
);
+3 -3
View File
@@ -76,8 +76,8 @@ mod tests {
#[cfg(test)]
mod reverse_mix_delegations {
use super::*;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::{coin, Order};
use mixnet_contract_common::Delegation;
@@ -87,7 +87,7 @@ mod tests {
let mut deps = test_helpers::init_contract();
let node_identity: IdentityKey = "foo".into();
let delegation_owner = Addr::unchecked("bar");
let delegation = coin(12345, MIX_DENOM.base);
let delegation = coin(12345, TEST_COIN_DENOM);
let dummy_data = Delegation::new(
delegation_owner.clone(),
@@ -125,7 +125,7 @@ mod tests {
let node_identity2: IdentityKey = "foo2".into();
let delegation_owner1 = Addr::unchecked("bar");
let delegation_owner2 = Addr::unchecked("bar2");
let delegation = coin(12345, MIX_DENOM.base);
let delegation = coin(12345, TEST_COIN_DENOM);
assert!(test_helpers::read_delegation(
deps.as_ref().storage,
@@ -4,9 +4,8 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
// use crate::contract::debug_with_visibility;
// use crate::contract::debug_with_visibility;
use crate::error::ContractError;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnet_contract_settings::storage::{self as mixnet_params_storage};
use crate::mixnodes::storage as mixnodes_storage;
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
Response, Storage, Uint128, WasmMsg,
@@ -74,7 +73,10 @@ pub(crate) fn _try_reconcile_all_delegation_events(
Ok(response)
}
fn validate_delegation_stake(mut delegation: Vec<Coin>) -> Result<Coin, ContractError> {
fn validate_delegation_stake(
mut delegation: Vec<Coin>,
mix_denom: String,
) -> Result<Coin, ContractError> {
// check if anything was put as delegation
if delegation.is_empty() {
return Err(ContractError::EmptyDelegation);
@@ -85,8 +87,8 @@ fn validate_delegation_stake(mut delegation: Vec<Coin>) -> Result<Coin, Contract
}
// check that the denomination is correct
if delegation[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom {});
if delegation[0].denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
// check that we have provided a non-zero amount in the delegation
@@ -104,7 +106,8 @@ pub(crate) fn try_delegate_to_mixnode(
mix_identity: IdentityKey,
) -> Result<Response, ContractError> {
// check if the delegation contains any funds of the appropriate denomination
let amount = validate_delegation_stake(info.funds)?;
let amount =
validate_delegation_stake(info.funds, mixnet_params_storage::mix_denom(deps.storage)?)?;
_try_delegate_to_mixnode(
deps,
@@ -124,7 +127,8 @@ pub(crate) fn try_delegate_to_mixnode_on_behalf(
delegate: String,
) -> Result<Response, ContractError> {
// check if the delegation contains any funds of the appropriate denomination
let amount = validate_delegation_stake(info.funds)?;
let amount =
validate_delegation_stake(info.funds, mixnet_params_storage::mix_denom(deps.storage)?)?;
_try_delegate_to_mixnode(
deps,
@@ -260,6 +264,7 @@ pub(crate) fn try_reconcile_undelegation(
pending_undelegate: &PendingUndelegate,
) -> Result<ReconcileUndelegateResponse, ContractError> {
let delegation_map = storage::delegations();
let mix_denom = mixnet_params_storage::mix_denom(storage)?;
// debug_with_visibility(api, "Reconciling undelegations");
@@ -389,7 +394,7 @@ pub(crate) fn try_reconcile_undelegation(
.as_ref()
.unwrap_or(&pending_undelegate.delegate())
.to_string(),
amount: coins(total_funds.u128(), MIX_DENOM.base),
amount: coins(total_funds.u128(), mix_denom.clone()),
})
} else {
None
@@ -401,10 +406,10 @@ pub(crate) fn try_reconcile_undelegation(
let msg = Some(VestingContractExecuteMsg::TrackUndelegation {
owner: pending_undelegate.delegate().as_str().to_string(),
mix_identity: pending_undelegate.mix_identity(),
amount: Coin::new(total_funds.u128(), MIX_DENOM.base),
amount: Coin::new(total_funds.u128(), mix_denom.clone()),
});
wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin()])?);
wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin(mix_denom)])?);
}
let event = new_undelegation_event(
@@ -468,6 +473,7 @@ mod tests {
use cosmwasm_std::coins;
use crate::support::tests;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers;
use super::*;
@@ -482,7 +488,7 @@ mod tests {
fn stake_cant_be_empty() {
assert_eq!(
Err(ContractError::EmptyDelegation),
validate_delegation_stake(vec![])
validate_delegation_stake(vec![], TEST_COIN_DENOM.to_string())
)
}
@@ -490,19 +496,24 @@ mod tests {
fn stake_must_have_single_coin_type() {
assert_eq!(
Err(ContractError::MultipleDenoms),
validate_delegation_stake(vec![
coin(123, MIX_DENOM.base),
coin(123, "BTC"),
coin(123, "DOGE")
])
validate_delegation_stake(
vec![
coin(123, TEST_COIN_DENOM),
coin(123, "BTC"),
coin(123, "DOGE")
],
TEST_COIN_DENOM.to_string()
)
)
}
#[test]
fn stake_coin_must_be_of_correct_type() {
assert_eq!(
Err(ContractError::WrongDenom {}),
validate_delegation_stake(coins(123, "DOGE"))
Err(ContractError::WrongDenom {
mix_denom: TEST_COIN_DENOM.to_string()
}),
validate_delegation_stake(coins(123, "DOGE"), TEST_COIN_DENOM.to_string())
)
}
@@ -510,16 +521,28 @@ mod tests {
fn stake_coin_must_have_value_greater_than_zero() {
assert_eq!(
Err(ContractError::EmptyDelegation),
validate_delegation_stake(coins(0, MIX_DENOM.base))
validate_delegation_stake(coins(0, TEST_COIN_DENOM), TEST_COIN_DENOM.to_string())
)
}
#[test]
fn stake_can_have_any_positive_value() {
// this might change in the future, but right now an arbitrary (positive) value can be delegated
assert!(validate_delegation_stake(coins(1, MIX_DENOM.base)).is_ok());
assert!(validate_delegation_stake(coins(123, MIX_DENOM.base)).is_ok());
assert!(validate_delegation_stake(coins(10000000000, MIX_DENOM.base)).is_ok());
assert!(validate_delegation_stake(
coins(1, TEST_COIN_DENOM),
TEST_COIN_DENOM.to_string()
)
.is_ok());
assert!(validate_delegation_stake(
coins(123, TEST_COIN_DENOM),
TEST_COIN_DENOM.to_string()
)
.is_ok());
assert!(validate_delegation_stake(
coins(10000000000, TEST_COIN_DENOM),
TEST_COIN_DENOM.to_string()
)
.is_ok());
}
}
@@ -542,7 +565,7 @@ mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("sender", &coins(123, MIX_DENOM.base)),
mock_info("sender", &coins(123, TEST_COIN_DENOM)),
"non-existent-mix-identity".into(),
)
);
@@ -558,7 +581,7 @@ mod tests {
deps.as_mut(),
);
let delegation_owner = Addr::unchecked("sender");
let delegation = coin(123, MIX_DENOM.base);
let delegation = coin(123, TEST_COIN_DENOM);
assert!(try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
@@ -615,7 +638,7 @@ mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
mock_info(delegation_owner.as_str(), &coins(123, TEST_COIN_DENOM)),
identity,
)
);
@@ -636,7 +659,7 @@ mod tests {
tests::fixtures::good_mixnode_pledge(),
deps.as_mut(),
);
let delegation = coin(123, MIX_DENOM.base);
let delegation = coin(123, TEST_COIN_DENOM);
let delegation_owner = Addr::unchecked("sender");
assert!(try_delegate_to_mixnode(
deps.as_mut(),
@@ -686,8 +709,8 @@ mod tests {
deps.as_mut(),
);
let delegation_owner = Addr::unchecked("sender");
let delegation1 = coin(100, MIX_DENOM.base);
let delegation2 = coin(50, MIX_DENOM.base);
let delegation1 = coin(100, TEST_COIN_DENOM);
let delegation2 = coin(50, TEST_COIN_DENOM);
let mut env = mock_env();
@@ -714,7 +737,7 @@ mod tests {
// let expected = Delegation::new(
// delegation_owner.clone(),
// identity.clone(),
// coin(delegation1.amount.u128() + delegation2.amount.u128(), MIX_DENOM.base),
// coin(delegation1.amount.u128() + delegation2.amount.u128(), TEST_COIN_DENOM),
// mock_env().block.height,
// None,
// );
@@ -749,7 +772,7 @@ mod tests {
deps.as_mut(),
);
let delegation_owner = Addr::unchecked("sender");
let delegation = coin(100, MIX_DENOM.base);
let delegation = coin(100, TEST_COIN_DENOM);
let env1 = mock_env();
let mut env2 = mock_env();
let initial_height = env1.block.height;
@@ -814,8 +837,8 @@ mod tests {
);
let delegation_owner1 = Addr::unchecked("sender1");
let delegation_owner2 = Addr::unchecked("sender2");
let delegation1 = coin(100, MIX_DENOM.base);
let delegation2 = coin(120, MIX_DENOM.base);
let delegation1 = coin(100, TEST_COIN_DENOM);
let delegation2 = coin(120, TEST_COIN_DENOM);
let env1 = mock_env();
let mut env2 = mock_env();
let initial_height = env1.block.height;
@@ -890,7 +913,7 @@ mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
mock_info(delegation_owner.as_str(), &coins(100, TEST_COIN_DENOM)),
identity.clone(),
)
.unwrap();
@@ -902,7 +925,7 @@ mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info(delegation_owner.as_str(), &coins(50, MIX_DENOM.base)),
mock_info(delegation_owner.as_str(), &coins(50, TEST_COIN_DENOM)),
identity,
)
);
@@ -927,14 +950,14 @@ mod tests {
assert!(try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
mock_info(delegation_owner.as_str(), &coins(123, TEST_COIN_DENOM)),
identity1.clone(),
)
.is_ok());
assert!(try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info(delegation_owner.as_str(), &coins(42, MIX_DENOM.base)),
mock_info(delegation_owner.as_str(), &coins(42, TEST_COIN_DENOM)),
identity2.clone(),
)
.is_ok());
@@ -944,7 +967,7 @@ mod tests {
let expected1 = Delegation::new(
delegation_owner.clone(),
identity1.clone(),
coin(123, MIX_DENOM.base),
coin(123, TEST_COIN_DENOM),
mock_env().block.height,
None,
);
@@ -952,7 +975,7 @@ mod tests {
let expected2 = Delegation::new(
delegation_owner.clone(),
identity2.clone(),
coin(42, MIX_DENOM.base),
coin(42, TEST_COIN_DENOM),
mock_env().block.height,
None,
);
@@ -988,8 +1011,8 @@ mod tests {
tests::fixtures::good_mixnode_pledge(),
deps.as_mut(),
);
let delegation1 = coin(123, MIX_DENOM.base);
let delegation2 = coin(234, MIX_DENOM.base);
let delegation1 = coin(123, TEST_COIN_DENOM);
let delegation2 = coin(234, TEST_COIN_DENOM);
assert!(try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
@@ -1025,7 +1048,7 @@ mod tests {
deps.as_mut(),
);
let delegation_owner = Addr::unchecked("sender");
let delegation_amount = coin(100, MIX_DENOM.base);
let delegation_amount = coin(100, TEST_COIN_DENOM);
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
@@ -1113,7 +1136,7 @@ mod tests {
// try_delegate_to_mixnode(
// deps.as_mut(),
// mock_env(),
// mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
// mock_info(delegation_owner.as_str(), &coins(100, TEST_COIN_DENOM)),
// identity.clone(),
// )
// .unwrap();
@@ -1132,7 +1155,7 @@ mod tests {
// let expected_response = Response::new()
// .add_message(BankMsg::Send {
// to_address: delegation_owner.clone().into(),
// amount: coins(100, MIX_DENOM.base),
// amount: coins(100, TEST_COIN_DENOM),
// })
// .add_event(new_undelegation_event(
// &delegation_owner,
@@ -1183,7 +1206,7 @@ mod tests {
// try_delegate_to_mixnode(
// deps.as_mut(),
// mock_env(),
// mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
// mock_info(delegation_owner.as_str(), &coins(100, TEST_COIN_DENOM)),
// identity.clone(),
// )
// .unwrap();
@@ -1202,7 +1225,7 @@ mod tests {
// let expected_response = Response::new()
// .add_message(BankMsg::Send {
// to_address: delegation_owner.clone().into(),
// amount: coins(100, MIX_DENOM.base),
// amount: coins(100, TEST_COIN_DENOM),
// })
// .add_event(new_undelegation_event(
// &delegation_owner,
@@ -1246,8 +1269,8 @@ mod tests {
);
let delegation_owner1 = Addr::unchecked("sender1");
let delegation_owner2 = Addr::unchecked("sender2");
let delegation1 = coin(123, MIX_DENOM.base);
let delegation2 = coin(234, MIX_DENOM.base);
let delegation1 = coin(123, TEST_COIN_DENOM);
let delegation2 = coin(234, TEST_COIN_DENOM);
assert!(try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
+4 -5
View File
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::MIX_DENOM;
use cosmwasm_std::{Addr, StdError};
use mixnet_contract_common::{error::MixnetContractError, IdentityKey};
use thiserror::Error;
@@ -33,14 +32,14 @@ pub enum ContractError {
#[error("MIXNET ({}): Unauthorized", line!())]
Unauthorized,
#[error("MIXNET ({}): Wrong coin denomination, you must send {}", line!(), MIX_DENOM.base)]
WrongDenom,
#[error("MIXNET ({}): Wrong coin denomination, you must send {mix_denom}", line!())]
WrongDenom { mix_denom: String },
#[error("MIXNET ({}): Received multiple coin types during staking", line!())]
MultipleDenoms,
#[error("MIXNET ({}): No coin was sent for the bonding, you must send {}", line!(), MIX_DENOM.base)]
NoBondFound,
#[error("MIXNET ({}): No coin was sent for the bonding, you must send {mix_denom}", line!())]
NoBondFound { mix_denom: String },
#[error("MIXNET ({}): Provided active set size is bigger than the rewarded set", line!())]
InvalidActiveSetSize,
+2 -2
View File
@@ -36,7 +36,7 @@ pub(crate) fn gateways<'a>() -> IndexedMap<'a, IdentityKeyRef<'a>, GatewayBond,
mod tests {
use super::super::storage;
use crate::support::tests;
use config::defaults::MIX_DENOM;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use cosmwasm_std::testing::MockStorage;
use cosmwasm_std::StdResult;
use cosmwasm_std::Storage;
@@ -84,7 +84,7 @@ mod tests {
let pledge_amount = 1000;
let gateway_bond = GatewayBond {
pledge_amount: coin(pledge_amount, MIX_DENOM.base),
pledge_amount: coin(pledge_amount, TEST_COIN_DENOM),
owner: node_owner,
block_height: 12_345,
gateway: Gateway {
+55 -17
View File
@@ -5,7 +5,6 @@ use super::storage;
use crate::error::ContractError;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::support::helpers::{ensure_no_existing_bond, validate_node_identity_signature};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
wasm_execute, Addr, BankMsg, Coin, DepsMut, Env, MessageInfo, Response, Uint128,
};
@@ -26,7 +25,8 @@ pub fn try_add_gateway(
.load(deps.storage)?
.params
.minimum_mixnode_pledge;
let pledge = validate_gateway_pledge(info.funds, minimum_pledge)?;
let mix_denom = mixnet_params_storage::mix_denom(deps.storage)?;
let pledge = validate_gateway_pledge(info.funds, minimum_pledge, mix_denom)?;
_try_add_gateway(
deps,
@@ -52,7 +52,8 @@ pub fn try_add_gateway_on_behalf(
.load(deps.storage)?
.params
.minimum_mixnode_pledge;
let pledge = validate_gateway_pledge(info.funds, minimum_pledge)?;
let mix_denom = mixnet_params_storage::mix_denom(deps.storage)?;
let pledge = validate_gateway_pledge(info.funds, minimum_pledge, mix_denom)?;
let proxy = info.sender;
_try_add_gateway(
@@ -138,6 +139,7 @@ pub(crate) fn _try_remove_gateway(
proxy: Option<Addr>,
) -> Result<Response, ContractError> {
let owner = deps.api.addr_validate(owner)?;
let mix_denom = mixnet_params_storage::mix_denom(deps.storage)?;
// try to find the node of the sender
let gateway_bond = match storage::gateways()
.idx
@@ -177,7 +179,7 @@ pub(crate) fn _try_remove_gateway(
amount: gateway_bond.pledge_amount(),
};
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_ucoin(mix_denom)])?;
response = response.add_message(track_unbond_message);
}
@@ -192,10 +194,11 @@ pub(crate) fn _try_remove_gateway(
fn validate_gateway_pledge(
mut pledge: Vec<Coin>,
minimum_pledge: Uint128,
mix_denom: String,
) -> Result<Coin, ContractError> {
// check if anything was put as bond
if pledge.is_empty() {
return Err(ContractError::NoBondFound);
return Err(ContractError::NoBondFound { mix_denom });
}
if pledge.len() > 1 {
@@ -203,8 +206,8 @@ fn validate_gateway_pledge(
}
// check that the denomination is correct
if pledge[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom {});
if pledge[0].denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
// check that we have at least 100 coins in our pledge
@@ -225,8 +228,8 @@ pub mod tests {
use crate::error::ContractError;
use crate::gateways::transactions::validate_gateway_pledge;
use crate::support::tests;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coins, BankMsg, Response};
use cosmwasm_std::{from_binary, Addr, Uint128};
@@ -238,7 +241,7 @@ pub mod tests {
// if we fail validation (by say not sending enough funds
let insufficient_bond = Into::<u128>::into(INITIAL_GATEWAY_PLEDGE) - 1;
let info = mock_info("anyone", &coins(insufficient_bond, MIX_DENOM.base));
let info = mock_info("anyone", &coins(insufficient_bond, TEST_COIN_DENOM));
let (msg, _) = tests::messages::valid_bond_gateway_msg("anyone");
// we are informed that we didn't send enough funds
@@ -544,13 +547,26 @@ pub mod tests {
#[test]
fn validating_gateway_bond() {
// you must send SOME funds
let result = validate_gateway_pledge(Vec::new(), INITIAL_GATEWAY_PLEDGE);
assert_eq!(result, Err(ContractError::NoBondFound));
let result = validate_gateway_pledge(
Vec::new(),
INITIAL_GATEWAY_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::NoBondFound {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
// you must send at least 100 coins...
let mut bond = tests::fixtures::good_gateway_pledge();
bond[0].amount = INITIAL_GATEWAY_PLEDGE.checked_sub(Uint128::new(1)).unwrap();
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
let result = validate_gateway_pledge(
bond.clone(),
INITIAL_GATEWAY_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::InsufficientGatewayBond {
@@ -562,18 +578,40 @@ pub mod tests {
// more than that is still fine
let mut bond = tests::fixtures::good_gateway_pledge();
bond[0].amount = INITIAL_GATEWAY_PLEDGE + Uint128::new(1);
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
let result = validate_gateway_pledge(
bond.clone(),
INITIAL_GATEWAY_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert!(result.is_ok());
// it must be sent in the defined denom!
let mut bond = tests::fixtures::good_gateway_pledge();
bond[0].denom = "baddenom".to_string();
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
assert_eq!(result, Err(ContractError::WrongDenom {}));
let result = validate_gateway_pledge(
bond.clone(),
INITIAL_GATEWAY_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::WrongDenom {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
let mut bond = tests::fixtures::good_gateway_pledge();
bond[0].denom = "foomp".to_string();
let result = validate_gateway_pledge(bond.clone(), INITIAL_GATEWAY_PLEDGE);
assert_eq!(result, Err(ContractError::WrongDenom {}));
let result = validate_gateway_pledge(
bond.clone(),
INITIAL_GATEWAY_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::WrongDenom {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
}
}
@@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct ContractState {
pub owner: Addr, // only the owner account can update state
pub mix_denom: String,
pub rewarding_validator_address: Addr,
pub params: ContractStateParams,
}
@@ -45,6 +45,7 @@ pub(crate) mod tests {
let dummy_state = ContractState {
owner: Addr::unchecked("someowner"),
mix_denom: String::from("unym"),
rewarding_validator_address: Addr::unchecked("monitor"),
params: ContractStateParams {
minimum_mixnode_pledge: 123u128.into(),
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ContractError;
use crate::mixnet_contract_settings::models::ContractState;
use cosmwasm_std::StdResult;
use cosmwasm_std::Storage;
@@ -11,10 +10,14 @@ use mixnet_contract_common::{Layer, LayerDistribution};
pub(crate) const CONTRACT_STATE: Item<'_, ContractState> = Item::new("config");
pub(crate) const LAYERS: Item<'_, LayerDistribution> = Item::new("layers");
pub fn rewarding_validator_address(storage: &dyn Storage) -> Result<String, ContractError> {
Ok(CONTRACT_STATE
pub fn rewarding_validator_address(storage: &dyn Storage) -> StdResult<String> {
CONTRACT_STATE
.load(storage)
.map(|state| state.rewarding_validator_address.to_string())?)
.map(|state| state.rewarding_validator_address.to_string())
}
pub fn mix_denom(storage: &dyn Storage) -> StdResult<String> {
CONTRACT_STATE.load(storage).map(|state| state.mix_denom)
}
pub fn increment_layer_count(storage: &mut dyn Storage, layer: Layer) -> StdResult<()> {
+7 -5
View File
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::MIX_DENOM;
use cosmwasm_std::{StdResult, Storage, Uint128};
use cw_storage_plus::{Index, IndexList, IndexedSnapshotMap, Map, Strategy, UniqueIndex};
use mixnet_contract_common::{
@@ -11,6 +10,8 @@ use mixnet_contract_common::{SphinxKey, U128};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use crate::mixnet_contract_settings::storage::mix_denom;
// storage prefixes
const TOTAL_DELEGATION_NAMESPACE: &str = "td";
const MIXNODES_PK_NAMESPACE: &str = "mn";
@@ -171,7 +172,7 @@ pub(crate) fn read_full_mixnode_bond(
Ok(Some(MixNodeBond {
pledge_amount: stored_bond.pledge_amount,
total_delegation: Coin {
denom: MIX_DENOM.base.to_owned(),
denom: mix_denom(storage)?,
amount: total_delegation.unwrap_or_default(),
},
owner: stored_bond.owner,
@@ -190,7 +191,8 @@ mod tests {
use super::super::storage;
use super::*;
use crate::support::tests;
use config::defaults::MIX_DENOM;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers::init_contract;
use cosmwasm_std::testing::MockStorage;
use cosmwasm_std::{coin, Addr, Uint128};
use mixnet_contract_common::{IdentityKey, MixNode};
@@ -211,7 +213,7 @@ mod tests {
#[test]
fn reading_mixnode_bond() {
let mut mock_storage = MockStorage::new();
let mut mock_storage = init_contract().storage;
let node_owner: Addr = Addr::unchecked("node-owner");
let node_identity: IdentityKey = "nodeidentity".into();
@@ -223,7 +225,7 @@ mod tests {
let pledge_value = 1000000000;
let mixnode_bond = StoredMixnodeBond {
pledge_amount: coin(pledge_value, MIX_DENOM.base),
pledge_amount: coin(pledge_value, TEST_COIN_DENOM),
owner: node_owner,
layer: Layer::One,
block_height: 12_345,
+59 -20
View File
@@ -3,11 +3,10 @@
use super::storage::{self, LAST_PM_UPDATE_TIME};
use crate::error::ContractError;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnet_contract_settings::storage::{self as mixnet_params_storage, mix_denom};
use crate::mixnodes::layer_queries::query_layer_distribution;
use crate::mixnodes::storage::StoredMixnodeBond;
use crate::support::helpers::{ensure_no_existing_bond, validate_node_identity_signature};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
wasm_execute, Addr, BankMsg, Coin, DepsMut, Env, MessageInfo, Response, Storage, Uint128,
};
@@ -48,7 +47,7 @@ pub fn try_add_mixnode(
.load(deps.storage)?
.params
.minimum_mixnode_pledge;
let pledge = validate_mixnode_pledge(info.funds, minimum_pledge)?;
let pledge = validate_mixnode_pledge(info.funds, minimum_pledge, mix_denom(deps.storage)?)?;
_try_add_mixnode(
deps,
@@ -74,7 +73,7 @@ pub fn try_add_mixnode_on_behalf(
.load(deps.storage)?
.params
.minimum_mixnode_pledge;
let pledge = validate_mixnode_pledge(info.funds, minimum_pledge)?;
let pledge = validate_mixnode_pledge(info.funds, minimum_pledge, mix_denom(deps.storage)?)?;
let proxy = info.sender;
_try_add_mixnode(
@@ -239,7 +238,8 @@ pub(crate) fn _try_remove_mixnode(
amount: mixnode_bond.pledge_amount(),
};
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
let track_unbond_message =
wasm_execute(proxy, &msg, vec![one_ucoin(mix_denom(deps.storage)?)])?;
response = response.add_message(track_unbond_message);
}
@@ -288,6 +288,7 @@ pub(crate) fn _try_update_mixnode_config(
.item(deps.storage, owner.clone())?
.ok_or(ContractError::NoAssociatedMixNodeBond { owner })?
.1;
let mix_denom = mix_denom(deps.storage)?;
if proxy != mixnode_bond.proxy {
return Err(ContractError::ProxyMismatch {
@@ -329,7 +330,9 @@ pub(crate) fn _try_update_mixnode_config(
mixnode_bond.block_height = env.block.height;
mixnode_bond
})
.ok_or(ContractError::NoBondFound)
.ok_or(ContractError::NoBondFound {
mix_denom: mix_denom.clone(),
})
},
)?;
@@ -342,7 +345,7 @@ pub(crate) fn _try_update_mixnode_config(
// and they could potentially leak 1 unym per transaction, altough I'm pretty sure transaction fees make that silly.
let return_one_ucoint = BankMsg::Send {
to_address: proxy.as_str().to_string(),
amount: vec![one_ucoin()],
amount: vec![one_ucoin(mix_denom)],
};
response = response.add_message(return_one_ucoint);
}
@@ -353,10 +356,11 @@ pub(crate) fn _try_update_mixnode_config(
fn validate_mixnode_pledge(
mut pledge: Vec<Coin>,
minimum_pledge: Uint128,
mix_denom: String,
) -> Result<Coin, ContractError> {
// check if anything was put as bond
if pledge.is_empty() {
return Err(ContractError::NoBondFound);
return Err(ContractError::NoBondFound { mix_denom });
}
if pledge.len() > 1 {
@@ -364,8 +368,8 @@ fn validate_mixnode_pledge(
}
// check that the denomination is correct
if pledge[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom {});
if pledge[0].denom != mix_denom {
return Err(ContractError::WrongDenom { mix_denom });
}
// check that we have at least MIXNODE_BOND coins in our pledge
@@ -386,8 +390,8 @@ pub mod tests {
use crate::error::ContractError;
use crate::mixnodes::transactions::validate_mixnode_pledge;
use crate::support::tests;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coins, BankMsg, Response};
use cosmwasm_std::{from_binary, Addr, Uint128};
@@ -402,7 +406,7 @@ pub mod tests {
// if we don't send enough funds
let insufficient_bond = Into::<u128>::into(INITIAL_MIXNODE_PLEDGE) - 1;
let info = mock_info("anyone", &coins(insufficient_bond, MIX_DENOM.base));
let info = mock_info("anyone", &coins(insufficient_bond, TEST_COIN_DENOM));
let (msg, _) = tests::messages::valid_bond_mixnode_msg("anyone");
// we are informed that we didn't send enough funds
@@ -808,13 +812,26 @@ pub mod tests {
#[test]
fn validating_mixnode_bond() {
// you must send SOME funds
let result = validate_mixnode_pledge(Vec::new(), INITIAL_MIXNODE_PLEDGE);
assert_eq!(result, Err(ContractError::NoBondFound));
let result = validate_mixnode_pledge(
Vec::new(),
INITIAL_MIXNODE_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::NoBondFound {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
// you must send at least 100 coins...
let mut bond = tests::fixtures::good_mixnode_pledge();
bond[0].amount = INITIAL_MIXNODE_PLEDGE.checked_sub(Uint128::new(1)).unwrap();
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
let result = validate_mixnode_pledge(
bond.clone(),
INITIAL_MIXNODE_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::InsufficientMixNodeBond {
@@ -826,19 +843,41 @@ pub mod tests {
// more than that is still fine
let mut bond = tests::fixtures::good_mixnode_pledge();
bond[0].amount = INITIAL_MIXNODE_PLEDGE + Uint128::new(1);
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
let result = validate_mixnode_pledge(
bond.clone(),
INITIAL_MIXNODE_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert!(result.is_ok());
// it must be sent in the defined denom!
let mut bond = tests::fixtures::good_mixnode_pledge();
bond[0].denom = "baddenom".to_string();
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
assert_eq!(result, Err(ContractError::WrongDenom {}));
let result = validate_mixnode_pledge(
bond.clone(),
INITIAL_MIXNODE_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::WrongDenom {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
let mut bond = tests::fixtures::good_mixnode_pledge();
bond[0].denom = "foomp".to_string();
let result = validate_mixnode_pledge(bond.clone(), INITIAL_MIXNODE_PLEDGE);
assert_eq!(result, Err(ContractError::WrongDenom {}));
let result = validate_mixnode_pledge(
bond.clone(),
INITIAL_MIXNODE_PLEDGE,
TEST_COIN_DENOM.to_string(),
);
assert_eq!(
result,
Err(ContractError::WrongDenom {
mix_denom: TEST_COIN_DENOM.to_string()
})
);
}
#[test]
+2 -2
View File
@@ -83,7 +83,7 @@ pub(crate) mod tests {
use crate::delegations::transactions::try_delegate_to_mixnode;
use crate::interval::storage::{save_epoch, save_epoch_reward_params};
use crate::rewards::transactions::try_reward_mixnode;
use config::defaults::MIX_DENOM;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use cosmwasm_std::{coin, Addr};
use mixnet_contract_common::{
Interval, RewardingResult, RewardingStatus, MIXNODE_DELEGATORS_PAGE_LIMIT,
@@ -187,7 +187,7 @@ pub(crate) mod tests {
env.clone(),
mock_info(
&*format!("delegator{:04}", i),
&[coin(200_000000, MIX_DENOM.base)],
&[coin(200_000000, TEST_COIN_DENOM)],
),
node_identity.clone(),
)
+31 -28
View File
@@ -10,11 +10,11 @@ use crate::contract::debug_with_visibility;
use crate::delegations::storage as delegations_storage;
use crate::delegations::transactions::_try_delegate_to_mixnode;
use crate::error::ContractError;
use crate::mixnet_contract_settings::storage::mix_denom;
use crate::mixnodes::storage::mixnodes;
use crate::mixnodes::storage::{self as mixnodes_storage, StoredMixnodeBond};
use crate::rewards::helpers;
use crate::support::helpers::{is_authorized, operator_cost_at_epoch};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, MessageInfo, Order, Response,
Storage, Uint128,
@@ -69,6 +69,7 @@ fn _try_claim_operator_reward(
proxy: Option<Addr>,
) -> Result<Response, ContractError> {
let owner = api.addr_validate(owner)?;
let mix_denom = mix_denom(storage)?;
let bond = match crate::mixnodes::storage::mixnodes()
.idx
@@ -105,7 +106,7 @@ fn _try_claim_operator_reward(
let return_tokens = BankMsg::Send {
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
amount: coins(reward.u128(), MIX_DENOM.base),
amount: coins(reward.u128(), mix_denom.clone()),
};
let mut response = Response::default()
@@ -115,10 +116,10 @@ fn _try_claim_operator_reward(
if let Some(proxy) = proxy {
let msg = Some(VestingContractExecuteMsg::TrackReward {
address: owner.to_string(),
amount: Coin::new(reward.u128(), MIX_DENOM.base),
amount: Coin::new(reward.u128(), mix_denom.clone()),
});
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin(mix_denom)])?;
response = response.add_message(wasm_msg);
}
@@ -134,6 +135,7 @@ pub fn _try_claim_delegator_reward(
proxy: Option<Addr>,
) -> Result<Response, ContractError> {
let owner = api.addr_validate(owner)?;
let mix_denom = mix_denom(storage)?;
let key = mixnet_contract_common::delegation::generate_storage_key(&owner, proxy.as_ref());
let reward = calculate_delegator_reward(storage, api, key.clone(), mix_identity)?;
@@ -153,7 +155,7 @@ pub fn _try_claim_delegator_reward(
let return_tokens = BankMsg::Send {
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
amount: coins(reward.u128(), MIX_DENOM.base),
amount: coins(reward.u128(), mix_denom.clone()),
};
let mut response =
@@ -169,10 +171,10 @@ pub fn _try_claim_delegator_reward(
if let Some(proxy) = proxy {
let msg = Some(VestingContractExecuteMsg::TrackReward {
address: owner.to_string(),
amount: Coin::new(reward.u128(), MIX_DENOM.base),
amount: Coin::new(reward.u128(), mix_denom.clone()),
});
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin(mix_denom)])?;
response = response.add_message(wasm_msg);
}
@@ -403,6 +405,7 @@ pub fn _try_compound_delegator_reward(
proxy: Option<Addr>,
) -> Result<Uint128, ContractError> {
let delegation_map = crate::delegations::storage::delegations();
let mix_denom = mix_denom(deps.storage)?;
let key = mixnet_contract_common::delegation::generate_storage_key(
&deps.api.addr_validate(owner_address)?,
@@ -438,7 +441,7 @@ pub fn _try_compound_delegator_reward(
owner_address,
Coin {
amount: compounded_delegation,
denom: MIX_DENOM.base.to_string(),
denom: mix_denom,
},
proxy,
)?;
@@ -724,9 +727,9 @@ pub mod tests {
use crate::rewards::transactions::try_reward_mixnode;
use crate::support::helpers::{current_operator_epoch_cost, epochs_in_interval};
use crate::support::tests;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::test_helpers;
use az::CheckedCast;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coin, coins, Addr, StdError, Timestamp, Uint128};
use mixnet_contract_common::events::{
@@ -744,7 +747,7 @@ pub mod tests {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let sender = rewarding_validator_address(&deps.storage).unwrap();
let info = mock_info(&sender, &coins(1000, MIX_DENOM.base));
let info = mock_info(&sender, &coins(1000, TEST_COIN_DENOM));
crate::interval::transactions::init_epoch(&mut deps.storage, env.clone()).unwrap();
// bond the node
@@ -885,7 +888,7 @@ pub mod tests {
let initial_bond = 10000_000000;
let initial_delegation = 20000_000000;
let mixnode_bond = StoredMixnodeBond {
pledge_amount: coin(initial_bond, MIX_DENOM.base),
pledge_amount: coin(initial_bond, TEST_COIN_DENOM),
owner: node_owner,
layer: Layer::One,
block_height: env.block.height,
@@ -925,7 +928,7 @@ pub mod tests {
&Delegation::new(
Addr::unchecked("delegator"),
node_identity.clone(),
coin(initial_delegation, MIX_DENOM.base),
coin(initial_delegation, TEST_COIN_DENOM),
env.block.height,
None,
),
@@ -1109,7 +1112,7 @@ pub mod tests {
assert_eq!(staking_supply, 100_000_000_000_000u128);
let sender = Addr::unchecked("alice");
let stake = coins(10_000_000_000, MIX_DENOM.base);
let stake = coins(10_000_000_000, TEST_COIN_DENOM);
let keypair = crypto::asymmetric::identity::KeyPair::new(&mut thread_rng());
let owner_signature = keypair
@@ -1160,14 +1163,14 @@ pub mod tests {
let node_owner: Addr = Addr::unchecked("johnny");
let node_identity_2 = test_helpers::add_mixnode(
node_owner.as_str(),
coins(10_000_000_000, MIX_DENOM.base),
coins(10_000_000_000, TEST_COIN_DENOM),
deps.as_mut(),
);
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
mock_info("alice_d1", &[coin(8000_000000, TEST_COIN_DENOM)]),
node_identity_1.clone(),
)
.unwrap();
@@ -1175,7 +1178,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alice_d2", &[coin(2000_000000, MIX_DENOM.base)]),
mock_info("alice_d2", &[coin(2000_000000, TEST_COIN_DENOM)]),
node_identity_1.clone(),
)
.unwrap();
@@ -1183,7 +1186,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("bob_d1", &[coin(8000_000000, MIX_DENOM.base)]),
mock_info("bob_d1", &[coin(8000_000000, TEST_COIN_DENOM)]),
node_identity_2.clone(),
)
.unwrap();
@@ -1191,7 +1194,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("bob_d2", &[coin(2000_000000, MIX_DENOM.base)]),
mock_info("bob_d2", &[coin(2000_000000, TEST_COIN_DENOM)]),
node_identity_2.clone(),
)
.unwrap();
@@ -1199,14 +1202,14 @@ pub mod tests {
let node_owner: Addr = Addr::unchecked("alicebob");
let node_identity_3 = test_helpers::add_mixnode(
node_owner.as_str(),
coins(10_000_000_000 * 2, MIX_DENOM.base),
coins(10_000_000_000 * 2, TEST_COIN_DENOM),
deps.as_mut(),
);
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alicebob_d1", &[coin(8000_000000 * 2, MIX_DENOM.base)]),
mock_info("alicebob_d1", &[coin(8000_000000 * 2, TEST_COIN_DENOM)]),
node_identity_3.clone(),
)
.unwrap();
@@ -1214,7 +1217,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alicebob_d2", &[coin(2000_000000 * 2, MIX_DENOM.base)]),
mock_info("alicebob_d2", &[coin(2000_000000 * 2, TEST_COIN_DENOM)]),
node_identity_3.clone(),
)
.unwrap();
@@ -1320,7 +1323,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
env.clone(),
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
mock_info("alice_d1", &[coin(8000_000000, TEST_COIN_DENOM)]),
node_identity_1.clone(),
)
.unwrap();
@@ -1559,14 +1562,14 @@ pub mod tests {
let node_owner: Addr = Addr::unchecked("alice");
let node_identity = test_helpers::add_mixnode(
node_owner.as_str(),
coins(10_000_000_000, MIX_DENOM.base),
coins(10_000_000_000, TEST_COIN_DENOM),
deps.as_mut(),
);
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
mock_info("alice_d1", &[coin(8000_000000, TEST_COIN_DENOM)]),
node_identity.clone(),
)
.unwrap();
@@ -1574,7 +1577,7 @@ pub mod tests {
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("alice_d2", &[coin(2000_000000, MIX_DENOM.base)]),
mock_info("alice_d2", &[coin(2000_000000, TEST_COIN_DENOM)]),
node_identity.clone(),
)
.unwrap();
@@ -1750,7 +1753,7 @@ pub mod tests {
#[allow(clippy::inconsistent_digit_grouping)]
let node_identity = test_helpers::add_mixnode(
node_owner.as_str(),
coins(10000_000_000, MIX_DENOM.base),
coins(10000_000_000, TEST_COIN_DENOM),
deps.as_mut(),
);
@@ -1777,7 +1780,7 @@ pub mod tests {
#[allow(clippy::inconsistent_digit_grouping)]
let node_identity = test_helpers::add_mixnode(
node_owner.as_str(),
coins(10000_000_000, MIX_DENOM.base),
coins(10000_000_000, TEST_COIN_DENOM),
deps.as_mut(),
);
@@ -1787,7 +1790,7 @@ pub mod tests {
env.clone(),
mock_info(
&*format!("delegator{:04}", i),
&[coin(2000_000000, MIX_DENOM.base)],
&[coin(2000_000000, TEST_COIN_DENOM)],
),
node_identity.clone(),
)
@@ -1,11 +1,13 @@
use crate::contract::INITIAL_MIXNODE_PLEDGE;
use crate::mixnodes::storage as mixnodes_storage;
use crate::{mixnodes::storage::StoredMixnodeBond, support::tests};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{coin, Addr, Coin};
use mixnet_contract_common::reward_params::NodeRewardParams;
use mixnet_contract_common::{Gateway, GatewayBond, Layer, MixNode};
pub const TEST_COIN_DENOM: &str = "unym";
pub const TEST_REWARDING_VALIDATOR_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub fn mix_node_fixture() -> MixNode {
MixNode {
host: "mix.node.org".to_string(),
@@ -37,7 +39,7 @@ pub fn gateway_bond_fixture(owner: &str) -> GatewayBond {
..tests::fixtures::gateway_fixture()
};
GatewayBond::new(
coin(50, MIX_DENOM.base),
coin(50, TEST_COIN_DENOM),
Addr::unchecked(owner),
12_345,
gateway,
@@ -47,7 +49,7 @@ pub fn gateway_bond_fixture(owner: &str) -> GatewayBond {
pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::StoredMixnodeBond {
StoredMixnodeBond::new(
coin(50, MIX_DENOM.base),
coin(50, TEST_COIN_DENOM),
Addr::unchecked(owner),
Layer::One,
12_345,
@@ -64,14 +66,14 @@ pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::Stor
pub fn good_mixnode_pledge() -> Vec<Coin> {
vec![Coin {
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
amount: INITIAL_MIXNODE_PLEDGE,
}]
}
pub fn good_gateway_pledge() -> Vec<Coin> {
vec![Coin {
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
amount: INITIAL_MIXNODE_PLEDGE,
}]
}
+6 -3
View File
@@ -17,7 +17,6 @@ pub mod test_helpers {
use crate::mixnodes::storage as mixnodes_storage;
use crate::mixnodes::transactions::try_add_mixnode;
use crate::support::tests;
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
use cosmwasm_std::testing::mock_dependencies;
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::testing::mock_info;
@@ -32,6 +31,9 @@ pub mod test_helpers {
use mixnet_contract_common::{Delegation, Gateway, IdentityKeyRef, InstantiateMsg, MixNode};
use rand::thread_rng;
use super::fixtures::TEST_COIN_DENOM;
use super::fixtures::TEST_REWARDING_VALIDATOR_ADDRESS;
pub fn add_mixnode(sender: &str, stake: Vec<Coin>, deps: DepsMut<'_>) -> String {
let keypair = crypto::asymmetric::identity::KeyPair::new(&mut thread_rng());
let owner_signature = keypair
@@ -85,7 +87,8 @@ pub mod test_helpers {
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
rewarding_validator_address: DEFAULT_NETWORK.rewarding_validator_address().to_string(),
rewarding_validator_address: TEST_REWARDING_VALIDATOR_ADDRESS.to_string(),
mixnet_denom: TEST_COIN_DENOM.to_string(),
};
let env = mock_env();
let info = mock_info("creator", &[]);
@@ -111,7 +114,7 @@ pub mod test_helpers {
let delegation = Delegation {
owner: Addr::unchecked(owner.into()),
node_identity: mix.into(),
amount: coin(12345, MIX_DENOM.base),
amount: coin(12345, TEST_COIN_DENOM),
block_height: block_height,
proxy: None,
};
@@ -1,4 +1,3 @@
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
from_binary,
testing::{mock_env, MockApi, MockQuerier, MockStorage},
@@ -10,6 +9,8 @@ use mixnet_contract_common::{
use crate::contract::query;
use super::fixtures::TEST_COIN_DENOM;
pub fn get_mix_nodes(deps: &mut OwnedDeps<MockStorage, MockApi, MockQuerier>) -> Vec<MixNodeBond> {
let result = query(
deps.as_ref(),
@@ -45,5 +46,5 @@ pub fn query_contract_balance(
deps: OwnedDeps<MockStorage, MockApi, MockQuerier>,
) -> Vec<Coin> {
let querier = deps.as_ref().querier;
vec![querier.query_balance(address, MIX_DENOM.base).unwrap()]
vec![querier.query_balance(address, TEST_COIN_DENOM).unwrap()]
}
@@ -29,7 +29,6 @@ serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" }
network-defaults = { path = "../../../common/network-defaults" }
[dev-dependencies]
cosmwasm-schema = { version = "1.0.0" }
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_binary, Addr, Binary, BlockInfo, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order,
to_binary, Binary, BlockInfo, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order,
Response, StdResult,
};
@@ -16,7 +16,6 @@ use cw3_fixed_multisig::state::{next_id, Ballot, Proposal, Votes, BALLOTS, PROPO
use cw4::{Cw4Contract, MemberChangedHookMsg, MemberDiff};
use cw_storage_plus::Bound;
use cw_utils::{maybe_addr, Expiration, ThresholdResponse};
use network_defaults::DEFAULT_NETWORK;
use crate::error::ContractError;
use crate::state::{Config, CONFIG};
@@ -40,11 +39,9 @@ pub fn instantiate(
})?);
// This might need to be changed via a migration, due to circular dependency
// of deploying the two contracts
let coconut_bandwidth_addr = Addr::unchecked(
DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.ok_or(ContractError::InvalidCoconutBandwidth {})?,
);
let coconut_bandwidth_addr = deps
.api
.addr_validate(&msg.coconut_bandwidth_contract_address)?;
let total_weight = group_addr.total_weight(&deps.querier)?;
msg.threshold.validate(total_weight)?;
@@ -461,6 +458,8 @@ mod tests {
const VOTER4: &str = "voter0004";
const VOTER5: &str = "voter0005";
const SOMEBODY: &str = "somebody";
const TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
fn member<T: Into<String>>(addr: T, weight: u64) -> Member {
Member {
@@ -513,9 +512,7 @@ mod tests {
proposal: ExecuteMsg,
voter: &str,
) -> AppResponse {
let proposer = DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.unwrap();
let proposer = TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string();
let res = app
.execute_contract(Addr::unchecked(proposer), flex_addr.clone(), &proposal, &[])
.unwrap();
@@ -541,6 +538,7 @@ mod tests {
group_addr: group.to_string(),
threshold,
max_voting_period,
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
};
app.instantiate_contract(flex_id, Addr::unchecked(OWNER), &msg, &[], "flex", None)
.unwrap()
@@ -576,9 +574,7 @@ mod tests {
init_funds: Vec<Coin>,
multisig_as_group_admin: bool,
) -> (Addr, Addr) {
let coconut_bandwidth_contract = DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.unwrap();
let coconut_bandwidth_contract = TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string();
// 1. Instantiate group contract with members (and OWNER as admin) and coconut bandwidth contract
let members = vec![
member(coconut_bandwidth_contract, 0),
@@ -658,6 +654,7 @@ mod tests {
quorum: Decimal::percent(1),
},
max_voting_period,
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
};
let err = app
.instantiate_contract(
@@ -679,6 +676,7 @@ mod tests {
group_addr: group_addr.to_string(),
threshold: Threshold::AbsoluteCount { weight: 100 },
max_voting_period,
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
};
let err = app
.instantiate_contract(
@@ -700,6 +698,7 @@ mod tests {
group_addr: group_addr.to_string(),
threshold: Threshold::AbsoluteCount { weight: 1 },
max_voting_period,
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
};
let flex_addr = app
.instantiate_contract(
@@ -772,11 +771,7 @@ mod tests {
};
let err = app
.execute_contract(
Addr::unchecked(
DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.unwrap(),
),
Addr::unchecked(TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string()),
flex_addr.clone(),
&proposal_wrong_exp,
&[],
@@ -851,9 +846,7 @@ mod tests {
.unwrap_err();
assert_eq!(ContractError::Unauthorized {}, err.downcast().unwrap());
let proposer = DEFAULT_NETWORK
.coconut_bandwidth_contract_address()
.unwrap();
let proposer = TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string();
let res = app
.execute_contract(
Addr::unchecked(&proposer),
-1
View File
@@ -16,7 +16,6 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
config = { path = "../../common/config" }
cosmwasm-std = { version = "1.0.0 "}
cw-storage-plus = { version = "0.13.4", features = ["iterator"] }
+18 -19
View File
@@ -1,13 +1,12 @@
use crate::errors::ContractError;
use crate::storage::{
account_from_address, locked_pledge_cap, update_locked_pledge_cap, ADMIN,
MIXNET_CONTRACT_ADDRESS,
MIXNET_CONTRACT_ADDRESS, MIX_DENOM,
};
use crate::traits::{
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
};
use crate::vesting::{populate_vesting_periods, Account};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse,
Response, Timestamp, Uint128,
@@ -36,6 +35,7 @@ pub fn instantiate(
// ADMIN is set to the address that instantiated the contract, TODO: make this updatable
ADMIN.save(deps.storage, &info.sender.to_string())?;
MIXNET_CONTRACT_ADDRESS.save(deps.storage, &msg.mixnet_contract_address)?;
MIX_DENOM.save(deps.storage, &msg.mix_denom)?;
Ok(Response::default())
}
@@ -167,11 +167,9 @@ pub fn try_withdraw_vested_coins(
info: MessageInfo,
deps: DepsMut<'_>,
) -> Result<Response, ContractError> {
if amount.denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom(
amount.denom,
MIX_DENOM.base.to_string(),
));
let mix_denom = MIX_DENOM.load(deps.storage)?;
if amount.denom != mix_denom {
return Err(ContractError::WrongDenom(amount.denom, mix_denom));
}
let address = info.sender.clone();
@@ -245,7 +243,8 @@ pub fn try_bond_gateway(
env: Env,
deps: DepsMut<'_>,
) -> Result<Response, ContractError> {
let pledge = validate_funds(&[amount])?;
let mix_denom = MIX_DENOM.load(deps.storage)?;
let pledge = validate_funds(&[amount], mix_denom)?;
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_bond_gateway(gateway, owner_signature, pledge, &env, deps.storage)
}
@@ -285,7 +284,8 @@ pub fn try_bond_mixnode(
env: Env,
deps: DepsMut<'_>,
) -> Result<Response, ContractError> {
let pledge = validate_funds(&[amount])?;
let mix_denom = MIX_DENOM.load(deps.storage)?;
let pledge = validate_funds(&[amount], mix_denom)?;
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_bond_mixnode(mix_node, owner_signature, pledge, &env, deps.storage)
}
@@ -345,7 +345,8 @@ fn try_delegate_to_mixnode(
env: Env,
deps: DepsMut<'_>,
) -> Result<Response, ContractError> {
let amount = validate_funds(&[amount])?;
let mix_denom = MIX_DENOM.load(deps.storage)?;
let amount = validate_funds(&[amount], mix_denom)?;
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
account.try_delegate_to_mixnode(mix_identity, amount, &env, deps.storage)
}
@@ -396,6 +397,7 @@ fn try_create_periodic_vesting_account(
if info.sender != ADMIN.load(deps.storage)? {
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
}
let mix_denom = MIX_DENOM.load(deps.storage)?;
let account_exists = account_from_address(owner_address, deps.storage, deps.api).is_ok();
if account_exists {
@@ -406,7 +408,7 @@ fn try_create_periodic_vesting_account(
let vesting_spec = vesting_spec.unwrap_or_default();
let coin = validate_funds(&info.funds)?;
let coin = validate_funds(&info.funds, mix_denom)?;
let owner_address = deps.api.addr_validate(owner_address)?;
let staking_address = if let Some(staking_address) = staking_address {
@@ -573,7 +575,7 @@ pub fn try_get_vested_coins(
deps: Deps<'_>,
) -> Result<Coin, ContractError> {
let account = account_from_address(vesting_account_address, deps.storage, deps.api)?;
account.get_vested_coins(block_time, &env)
account.get_vested_coins(block_time, &env, deps.storage)
}
pub fn try_get_vesting_coins(
@@ -583,7 +585,7 @@ pub fn try_get_vesting_coins(
deps: Deps<'_>,
) -> Result<Coin, ContractError> {
let account = account_from_address(vesting_account_address, deps.storage, deps.api)?;
account.get_vesting_coins(block_time, &env)
account.get_vesting_coins(block_time, &env, deps.storage)
}
pub fn try_get_start_time(
@@ -630,7 +632,7 @@ pub fn try_get_delegated_vesting(
account.get_delegated_vesting(block_time, &env, deps.storage)
}
fn validate_funds(funds: &[Coin]) -> Result<Coin, ContractError> {
fn validate_funds(funds: &[Coin], mix_denom: String) -> Result<Coin, ContractError> {
if funds.is_empty() || funds[0].amount.is_zero() {
return Err(ContractError::EmptyFunds);
}
@@ -639,11 +641,8 @@ fn validate_funds(funds: &[Coin]) -> Result<Coin, ContractError> {
return Err(ContractError::MultipleDenoms);
}
if funds[0].denom != MIX_DENOM.base {
return Err(ContractError::WrongDenom(
funds[0].denom.clone(),
MIX_DENOM.base.to_string(),
));
if funds[0].denom != mix_denom {
return Err(ContractError::WrongDenom(funds[0].denom.clone(), mix_denom));
}
Ok(funds[0].clone())
+1
View File
@@ -17,6 +17,7 @@ const GATEWAY_PLEDGES: Map<'_, u32, PledgeData> = Map::new("gtw");
pub const DELEGATIONS: Map<'_, (u32, IdentityKey, BlockHeight), Uint128> = Map::new("dlg");
pub const ADMIN: Item<'_, String> = Item::new("adm");
pub const MIXNET_CONTRACT_ADDRESS: Item<'_, String> = Item::new("mix");
pub const MIX_DENOM: Item<'_, String> = Item::new("den");
pub const LOCKED_PLEDGE_CAP: Item<'_, Uint128> = Item::new("lck");
pub fn locked_pledge_cap(storage: &dyn Storage) -> Uint128 {
+5 -3
View File
@@ -2,15 +2,17 @@
pub mod helpers {
use crate::contract::instantiate;
use crate::vesting::{populate_vesting_periods, Account};
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
use cosmwasm_std::{Addr, Coin, Empty, Env, MemoryStorage, OwnedDeps, Storage, Uint128};
use vesting_contract_common::messages::{InitMsg, VestingSpecification};
pub const TEST_COIN_DENOM: &str = "unym";
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies();
let msg = InitMsg {
mixnet_contract_address: "test".to_string(),
mix_denom: TEST_COIN_DENOM.to_string(),
};
let env = mock_env();
let info = mock_info("admin", &[]);
@@ -31,7 +33,7 @@ pub mod helpers {
Some(Addr::unchecked("staking")),
Coin {
amount: Uint128::new(1_000_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
start_time_ts,
periods,
@@ -50,7 +52,7 @@ pub mod helpers {
Some(Addr::unchecked("staking")),
Coin {
amount: Uint128::new(1_000_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
start_time,
periods,
@@ -34,11 +34,13 @@ pub trait VestingAccount {
&self,
block_time: Option<Timestamp>,
env: &Env,
storage: &dyn Storage,
) -> Result<Coin, ContractError>;
fn get_vesting_coins(
&self,
block_time: Option<Timestamp>,
env: &Env,
storage: &dyn Storage,
) -> Result<Coin, ContractError>;
fn get_start_time(&self) -> Timestamp;
@@ -2,6 +2,7 @@ use crate::errors::ContractError;
use crate::storage::locked_pledge_cap;
use crate::storage::save_delegation;
use crate::storage::MIXNET_CONTRACT_ADDRESS;
use crate::storage::MIX_DENOM;
use crate::traits::DelegatingAccount;
use crate::traits::VestingAccount;
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
@@ -28,7 +29,7 @@ impl DelegatingAccount for Account {
let compound_delegator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new().add_message(compound_delegator_reward_msg))
@@ -46,7 +47,7 @@ impl DelegatingAccount for Account {
let compound_delegator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new().add_message(compound_delegator_reward_msg))
@@ -118,7 +119,7 @@ impl DelegatingAccount for Account {
let undelegate_from_mixnode = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new()
@@ -2,6 +2,7 @@ use super::PledgeData;
use crate::errors::ContractError;
use crate::storage::locked_pledge_cap;
use crate::storage::MIXNET_CONTRACT_ADDRESS;
use crate::storage::MIX_DENOM;
use crate::traits::GatewayBondingAccount;
use crate::traits::VestingAccount;
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
@@ -76,7 +77,7 @@ impl GatewayBondingAccount for Account {
let unbond_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new()
@@ -1,6 +1,7 @@
use crate::errors::ContractError;
use crate::storage::locked_pledge_cap;
use crate::storage::MIXNET_CONTRACT_ADDRESS;
use crate::storage::MIX_DENOM;
use crate::traits::MixnodeBondingAccount;
use crate::traits::VestingAccount;
use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
@@ -24,7 +25,7 @@ impl MixnodeBondingAccount for Account {
let compound_operator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new().add_message(compound_operator_reward_msg))
@@ -41,7 +42,7 @@ impl MixnodeBondingAccount for Account {
let compound_operator_reward_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new().add_message(compound_operator_reward_msg))
@@ -60,7 +61,7 @@ impl MixnodeBondingAccount for Account {
let update_mixnode_config_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new()
@@ -130,7 +131,7 @@ impl MixnodeBondingAccount for Account {
let unbond_msg = wasm_execute(
MIXNET_CONTRACT_ADDRESS.load(storage)?,
&msg,
vec![one_ucoin()],
vec![one_ucoin(MIX_DENOM.load(storage)?)],
)?;
Ok(Response::new()
@@ -1,7 +1,6 @@
use crate::errors::ContractError;
use crate::storage::{delete_account, save_account, DELEGATIONS};
use crate::storage::{delete_account, save_account, DELEGATIONS, MIX_DENOM};
use crate::traits::VestingAccount;
use config::defaults::MIX_DENOM;
use cosmwasm_std::{Addr, Coin, Env, Order, Storage, Timestamp, Uint128};
use vesting_contract_common::{OriginalVestingResponse, Period};
@@ -33,7 +32,7 @@ impl VestingAccount for Account {
// Returns 0 in case of underflow. Which is fine, as the amount of pledged and delegated tokens can be larger then vesting_coins due to rewards and vesting periods expiring
Ok(Coin {
amount: Uint128::new(
self.get_vesting_coins(block_time, env)?
self.get_vesting_coins(block_time, env, storage)?
.amount
.u128()
.saturating_sub(
@@ -47,7 +46,7 @@ impl VestingAccount for Account {
.u128(),
),
),
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
@@ -63,7 +62,7 @@ impl VestingAccount for Account {
.u128()
.saturating_sub(self.locked_coins(block_time, env, storage)?.amount.u128()),
),
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
@@ -71,22 +70,24 @@ impl VestingAccount for Account {
&self,
block_time: Option<Timestamp>,
env: &Env,
storage: &dyn Storage,
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
let period = self.get_current_vesting_period(block_time);
let denom = MIX_DENOM.load(storage)?;
let amount = match period {
Period::Before => Coin {
amount: Uint128::new(0),
denom: MIX_DENOM.base.to_string(),
denom,
},
Period::In(idx) => Coin {
amount: Uint128::new(self.tokens_per_period()? * idx as u128),
denom: MIX_DENOM.base.to_string(),
denom,
},
Period::After => Coin {
amount: self.coin.amount,
denom: MIX_DENOM.base.to_string(),
denom,
},
};
Ok(amount)
@@ -96,11 +97,12 @@ impl VestingAccount for Account {
&self,
block_time: Option<Timestamp>,
env: &Env,
storage: &dyn Storage,
) -> Result<Coin, ContractError> {
Ok(Coin {
amount: self.get_original_vesting().amount().amount
- self.get_vested_coins(block_time, env)?.amount,
denom: MIX_DENOM.base.to_string(),
- self.get_vested_coins(block_time, env, storage)?.amount,
denom: MIX_DENOM.load(storage)?,
})
}
@@ -130,7 +132,7 @@ impl VestingAccount for Account {
let period = self.get_current_vesting_period(block_time);
let withdrawn = self.load_withdrawn(storage)?;
let max_available = self
.get_vested_coins(Some(block_time), env)?
.get_vested_coins(Some(block_time), env, storage)?
.amount
.saturating_sub(withdrawn);
let start_time = match period {
@@ -152,7 +154,7 @@ impl VestingAccount for Account {
Ok(Coin {
amount,
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
@@ -170,7 +172,7 @@ impl VestingAccount for Account {
Ok(Coin {
amount,
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
@@ -182,7 +184,7 @@ impl VestingAccount for Account {
) -> Result<Coin, ContractError> {
let block_time = block_time.unwrap_or(env.block.time);
let period = self.get_current_vesting_period(block_time);
let max_vested = self.get_vested_coins(Some(block_time), env)?;
let max_vested = self.get_vested_coins(Some(block_time), env, storage)?;
let start_time = match period {
Period::Before => 0,
Period::After => u64::MAX,
@@ -206,7 +208,7 @@ impl VestingAccount for Account {
Ok(Coin {
amount,
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
@@ -226,12 +228,12 @@ impl VestingAccount for Account {
let amount = bond.amount().amount - bonded_free.amount;
Ok(Coin {
amount,
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
} else {
Ok(Coin {
amount: Uint128::zero(),
denom: MIX_DENOM.base.to_string(),
denom: MIX_DENOM.load(storage)?,
})
}
}
+49 -30
View File
@@ -39,12 +39,11 @@ mod tests {
use crate::contract::execute;
use crate::storage::load_account;
use crate::support::tests::helpers::{
init_contract, vesting_account_mid_fixture, vesting_account_new_fixture,
init_contract, vesting_account_mid_fixture, vesting_account_new_fixture, TEST_COIN_DENOM,
};
use crate::traits::DelegatingAccount;
use crate::traits::VestingAccount;
use crate::traits::{GatewayBondingAccount, MixnodeBondingAccount};
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coins, Addr, Coin, Timestamp, Uint128};
use mixnet_contract_common::{Gateway, MixNode};
@@ -55,7 +54,7 @@ mod tests {
fn test_account_creation() {
let mut deps = init_contract();
let env = mock_env();
let info = mock_info("not_admin", &coins(1_000_000_000_000, MIX_DENOM.base));
let info = mock_info("not_admin", &coins(1_000_000_000_000, TEST_COIN_DENOM));
let msg = ExecuteMsg::CreateAccount {
owner_address: "owner".to_string(),
staking_address: Some("staking".to_string()),
@@ -65,7 +64,7 @@ mod tests {
let response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
assert!(response.is_err());
let info = mock_info("admin", &coins(1_000_000_000_000, MIX_DENOM.base));
let info = mock_info("admin", &coins(1_000_000_000_000, TEST_COIN_DENOM));
let _response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
let created_account = load_account(&Addr::unchecked("owner"), &deps.storage)
.unwrap()
@@ -131,7 +130,7 @@ mod tests {
let msg = ExecuteMsg::WithdrawVestedCoins {
amount: Coin {
amount: Uint128::new(1),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
};
let info = mock_info("new_owner", &[]);
@@ -186,8 +185,12 @@ mod tests {
Timestamp::from_seconds(account.start_time().seconds() + vesting_period + 1);
let current_period = account.get_current_vesting_period(block_time);
assert_eq!(current_period, Period::In(1));
let vested_coins = account.get_vested_coins(Some(block_time), &env).unwrap();
let vesting_coins = account.get_vesting_coins(Some(block_time), &env).unwrap();
let vested_coins = account
.get_vested_coins(Some(block_time), &env, &deps.storage)
.unwrap();
let vesting_coins = account
.get_vesting_coins(Some(block_time), &env, &deps.storage)
.unwrap();
assert_eq!(
vested_coins.amount,
Uint128::new(
@@ -207,8 +210,12 @@ mod tests {
Timestamp::from_seconds(account.start_time().seconds() + 5 * vesting_period + 1);
let current_period = account.get_current_vesting_period(block_time);
assert_eq!(current_period, Period::In(5));
let vested_coins = account.get_vested_coins(Some(block_time), &env).unwrap();
let vesting_coins = account.get_vesting_coins(Some(block_time), &env).unwrap();
let vested_coins = account
.get_vested_coins(Some(block_time), &env, &deps.storage)
.unwrap();
let vesting_coins = account
.get_vesting_coins(Some(block_time), &env, &deps.storage)
.unwrap();
assert_eq!(
vested_coins.amount,
Uint128::new(
@@ -230,8 +237,12 @@ mod tests {
);
let current_period = account.get_current_vesting_period(block_time);
assert_eq!(current_period, Period::After);
let vested_coins = account.get_vested_coins(Some(block_time), &env).unwrap();
let vesting_coins = account.get_vesting_coins(Some(block_time), &env).unwrap();
let vested_coins = account
.get_vested_coins(Some(block_time), &env, &deps.storage)
.unwrap();
let vesting_coins = account
.get_vesting_coins(Some(block_time), &env, &deps.storage)
.unwrap();
assert_eq!(
vested_coins.amount,
Uint128::new(account.get_original_vesting().amount().amount.u128())
@@ -245,8 +256,10 @@ mod tests {
let env = mock_env();
let account = vesting_account_mid_fixture(&mut deps.storage, &env);
let vested_coins = account.get_vested_coins(None, &env).unwrap();
let vesting_coins = account.get_vesting_coins(None, &env).unwrap();
let vested_coins = account.get_vested_coins(None, &env, &deps.storage).unwrap();
let vesting_coins = account
.get_vesting_coins(None, &env, &deps.storage)
.unwrap();
let locked_coins = account.locked_coins(None, &env, &mut deps.storage).unwrap();
assert_eq!(vested_coins.amount, Uint128::new(250_000_000_000));
assert_eq!(vesting_coins.amount, Uint128::new(750_000_000_000));
@@ -262,7 +275,7 @@ mod tests {
let delegation = Coin {
amount: Uint128::new(90_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
};
let ok = account.try_delegate_to_mixnode(
@@ -273,8 +286,10 @@ mod tests {
);
assert!(ok.is_ok());
let vested_coins = account.get_vested_coins(None, &env).unwrap();
let vesting_coins = account.get_vesting_coins(None, &env).unwrap();
let vested_coins = account.get_vested_coins(None, &env, &deps.storage).unwrap();
let vesting_coins = account
.get_vesting_coins(None, &env, &deps.storage)
.unwrap();
assert_eq!(vested_coins.amount, Uint128::new(250_000_000_000));
assert_eq!(vesting_coins.amount, Uint128::new(750_000_000_000));
@@ -333,8 +348,10 @@ mod tests {
let withdrawn = account.load_withdrawn(&deps.storage).unwrap();
assert_eq!(withdrawn, Uint128::new(250_000_000_000));
let vested_coins = account.get_vested_coins(None, &env).unwrap();
let vesting_coins = account.get_vesting_coins(None, &env).unwrap();
let vested_coins = account.get_vested_coins(None, &env, &deps.storage).unwrap();
let vesting_coins = account
.get_vesting_coins(None, &env, &deps.storage)
.unwrap();
let locked_coins = account.locked_coins(None, &env, &mut deps.storage).unwrap();
assert_eq!(vested_coins.amount, Uint128::new(250_000_000_000));
assert_eq!(vesting_coins.amount, Uint128::new(750_000_000_000));
@@ -352,8 +369,10 @@ mod tests {
);
assert!(ok.is_ok());
let vested_coins = account.get_vested_coins(None, &env).unwrap();
let vesting_coins = account.get_vesting_coins(None, &env).unwrap();
let vested_coins = account.get_vested_coins(None, &env, &deps.storage).unwrap();
let vesting_coins = account
.get_vesting_coins(None, &env, &deps.storage)
.unwrap();
let locked_coins = account.locked_coins(None, &env, &mut deps.storage).unwrap();
assert_eq!(vested_coins.amount, Uint128::new(250_000_000_000));
assert_eq!(vesting_coins.amount, Uint128::new(750_000_000_000));
@@ -388,7 +407,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(1_000_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -399,7 +418,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(90_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -411,7 +430,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(20_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -426,7 +445,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(500_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -522,7 +541,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(1_000_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -534,7 +553,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(90_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -550,7 +569,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(10_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -642,7 +661,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(1_000_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -654,7 +673,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(90_000_000_000),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
@@ -670,7 +689,7 @@ mod tests {
"alice".to_string(),
Coin {
amount: Uint128::new(500_000_000_001),
denom: MIX_DENOM.base.to_string(),
denom: TEST_COIN_DENOM.to_string(),
},
&env,
&mut deps.storage,
+20
View File
@@ -0,0 +1,20 @@
CONFIGURED=true
RUST_LOG=info
RUST_BACKTRACE=1
BECH32_PREFIX=n
MIX_DENOM=unym
MIX_DENOM_DISPLAY=nym
STAKE_DENOM=unyx
STAKE_DENOM_DISPLAY=nyx
DENOMS_EXPONENT=6
MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g
VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
MULTISIG_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://127.0.0.1:8090"
NYMD_VALIDATOR="https://rpc.nyx.nodes.guru/"
API_VALIDATOR="https://validator.nymtech.net/api/"
+20
View File
@@ -0,0 +1,20 @@
CONFIGURED=true
RUST_LOG=info
RUST_BACKTRACE=1
BECH32_PREFIX=n
MIX_DENOM=unym
MIX_DENOM_DISPLAY=nym
STAKE_DENOM=unyx
STAKE_DENOM_DISPLAY=nyx
DENOMS_EXPONENT=6
MIXNET_CONTRACT_ADDRESS=n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep
VESTING_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n1ghd753shjuwexxywmgs4xz7x2q732vcn7ty4yw
MULTISIG_CONTRACT_ADDRESS=n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs
REWARDING_VALIDATOR_ADDRESS=n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0"
NYMD_VALIDATOR="https://qa-validator.nymtech.net"
API_VALIDATOR="https://qa-validator-api.nymtech.net/api"
+1
View File
@@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
chrono = { version = "0.4.19", features = ["serde"] }
clap = { version = "3.2.8", features = ["cargo", "derive"] }
humantime-serde = "1.0"
isocountry = "0.3.2"
itertools = "0.10.3"
+14 -10
View File
@@ -1,6 +1,9 @@
use network_defaults::{default_api_endpoints, default_nymd_endpoints, DEFAULT_NETWORK};
use network_defaults::{
var_names::{API_VALIDATOR, NYMD_VALIDATOR},
NymNetworkDetails,
};
use reqwest::Url;
use std::sync::Arc;
use std::{str::FromStr, sync::Arc};
use validator_client::nymd::QueryNymdClient;
// since this is just a query client, we don't need any locking mechanism to keep sequence numbers in check
@@ -23,16 +26,17 @@ impl ThreadsafeValidatorClient {
}
pub(crate) fn new_validator_client() -> ThreadsafeValidatorClient {
let nymd_url = default_nymd_endpoints()[0].clone();
let api_url = default_api_endpoints()[0].clone();
let nymd_url = Url::from_str(&std::env::var(NYMD_VALIDATOR).expect("nymd validator not set"))
.expect("nymd validator not in url format");
let api_url = Url::from_str(&std::env::var(API_VALIDATOR).expect("nymd validator not set"))
.expect("nymd validator not in url format");
let client_config =
validator_client::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
.expect("failed to construct valid validator client config with the provided network")
.with_urls(nymd_url, api_url);
let details = NymNetworkDetails::new_from_env();
let client_config = validator_client::Config::try_from_nym_network_details(&details)
.expect("failed to construct valid validator client config with the provided network")
.with_urls(nymd_url, api_url);
ThreadsafeValidatorClient(Arc::new(
validator_client::Client::new_query(client_config, DEFAULT_NETWORK)
.expect("Failed to connect to nymd!"),
validator_client::Client::new_query(client_config).expect("Failed to connect to nymd!"),
))
}
+12
View File
@@ -0,0 +1,12 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the explorer api.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
}
+5
View File
@@ -3,10 +3,13 @@ extern crate rocket;
#[macro_use]
extern crate rocket_okapi;
use clap::Parser;
use log::info;
use network_defaults::setup_env;
pub(crate) mod cache;
mod client;
pub(crate) mod commands;
mod country_statistics;
mod gateways;
mod http;
@@ -24,6 +27,8 @@ const COUNTRY_DATA_REFRESH_INTERVAL: u64 = 60 * 15; // every 15 minutes
#[tokio::main]
async fn main() {
setup_logging();
let args = commands::Cli::parse();
setup_env(args.config_env_file);
let mut explorer_api = ExplorerApi::new();
explorer_api.run().await;
}
+3
View File
@@ -156,6 +156,8 @@ pub async fn execute(args: &Init) {
#[cfg(test)]
mod tests {
use network_defaults::var_names::BECH32_PREFIX;
use crate::node::{storage::InMemStorage, Gateway};
use super::*;
@@ -180,6 +182,7 @@ mod tests {
#[cfg(all(feature = "eth", not(feature = "coconut")))]
eth_endpoint: "".to_string(),
};
std::env::set_var(BECH32_PREFIX, "n");
let config = Config::new(&args.id);
let config = override_config(config, OverrideConfig::from(args.clone()));
+19 -1
View File
@@ -7,6 +7,9 @@ use crate::{config::Config, Cli};
use clap::Subcommand;
use colored::Colorize;
use crypto::bech32_address_validation;
use network_defaults::var_names::{
API_VALIDATOR, BECH32_PREFIX, CONFIGURED, NYMD_VALIDATOR, STATISTICS_SERVICE_DOMAIN_ADDRESS,
};
use url::Url;
pub(crate) mod init;
@@ -109,14 +112,28 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
.parse()
.expect("the provided statistics service url is invalid!"),
);
} else if std::env::var(CONFIGURED).is_ok() {
let raw_url = std::env::var(STATISTICS_SERVICE_DOMAIN_ADDRESS)
.expect("statistics service url not set");
config = config.with_custom_statistics_service_url(
raw_url
.parse()
.expect("the provided statistics service url is invalid"),
)
}
if let Some(raw_validators) = args.validator_apis {
config = config.with_custom_validator_apis(parse_validators(&raw_validators));
} else if std::env::var(CONFIGURED).is_ok() {
let raw_validators = std::env::var(API_VALIDATOR).expect("api validator not set");
config = config.with_custom_validator_apis(parse_validators(&raw_validators))
}
if let Some(raw_validators) = args.validators {
config = config.with_custom_validator_nymd(parse_validators(&raw_validators));
} else if std::env::var(CONFIGURED).is_ok() {
let raw_validators = std::env::var(NYMD_VALIDATOR).expect("nymd validator not set");
config = config.with_custom_validator_nymd(parse_validators(&raw_validators))
}
if let Some(wallet_address) = args.wallet_address {
@@ -166,6 +183,7 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
/// Ensures that a given bech32 address is valid, or exits
pub(crate) fn validate_bech32_address_or_exit(address: &str) {
let prefix = std::env::var(BECH32_PREFIX).expect("bech32 prefix not set");
if let Err(bech32_address_validation::Bech32Error::DecodeFailed(err)) =
bech32_address_validation::try_bech32_decode(address)
{
@@ -176,7 +194,7 @@ pub(crate) fn validate_bech32_address_or_exit(address: &str) {
}
if let Err(bech32_address_validation::Bech32Error::WrongPrefix(err)) =
bech32_address_validation::validate_bech32_prefix(address)
bech32_address_validation::validate_bech32_prefix(&prefix, address)
{
let error_message = format!("Error: wallet address type is wrong, {}", err).red();
println!("{}", error_message);
+1 -9
View File
@@ -3,7 +3,6 @@
use crate::config::{Config, MISSING_VALUE};
use clap::Args;
use config::defaults::default_api_endpoints;
use config::NymConfig;
use std::fmt::Display;
use std::process;
@@ -104,14 +103,7 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
let upgraded_config = config
.with_custom_version(to_version.to_string().as_ref())
.with_custom_validator_apis(default_api_endpoints());
let upgraded_config = config.with_custom_version(to_version.to_string().as_ref());
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {:?}", err);
+4 -4
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use config::defaults::*;
use config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT};
use config::NymConfig;
use log::error;
use serde::{Deserialize, Serialize};
@@ -422,9 +422,9 @@ impl Default for Gateway {
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
enabled_statistics: false,
statistics_service_url: default_statistics_service_url(),
validator_api_urls: default_api_endpoints(),
validator_nymd_urls: default_nymd_endpoints(),
statistics_service_url: Url::from_str("http://127.0.0.1").unwrap(),
validator_api_urls: vec![],
validator_nymd_urls: vec![],
cosmos_mnemonic: bip39::Mnemonic::from_str("exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day").unwrap(),
nym_root_directory: Config::default_root_directory(),
persistent_storage: Default::default(),
+7 -6
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, Parser};
use network_defaults::DEFAULT_NETWORK;
use network_defaults::setup_env;
use once_cell::sync::OnceCell;
mod commands;
@@ -19,13 +19,16 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, about, long_version = long_version_static())]
struct Cli {
/// Path pointing to an env file that configures the gateway.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: commands::Commands,
}
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
LONG_VERSION
@@ -33,6 +36,7 @@ async fn main() {
.expect("Failed to set long about text");
let args = Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(args).await;
}
@@ -64,7 +68,6 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -81,9 +84,7 @@ fn long_version() -> String {
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
env!("VERGEN_CARGO_PROFILE")
)
}
@@ -6,7 +6,6 @@ use std::time::{Duration, SystemTime};
use log::*;
use coconut_interface::{Credential, VerificationKey};
use network_defaults::MIX_DENOM;
use validator_client::{
nymd::{
cosmwasm_client::logs::find_attribute,
@@ -24,6 +23,7 @@ const MAX_FEEGRANT_UNYM: u128 = 10000;
pub(crate) struct CoconutVerifier {
api_clients: Vec<ApiClient>,
nymd_client: NymdClient<SigningNymdClient>,
mix_denom_base: String,
aggregated_verification_key: VerificationKey,
}
@@ -31,6 +31,7 @@ impl CoconutVerifier {
pub fn new(
api_clients: Vec<ApiClient>,
nymd_client: NymdClient<SigningNymdClient>,
mix_denom_base: String,
aggregated_verification_key: VerificationKey,
) -> Result<Self, RequestHandlingError> {
if api_clients.is_empty() {
@@ -42,6 +43,7 @@ impl CoconutVerifier {
Ok(CoconutVerifier {
api_clients,
nymd_client,
mix_denom_base,
aggregated_verification_key,
})
}
@@ -58,7 +60,10 @@ impl CoconutVerifier {
let res = self
.nymd_client
.spend_credential(
Coin::new(credential.voucher_value().into(), MIX_DENOM.base),
Coin::new(
credential.voucher_value().into(),
self.mix_denom_base.clone(),
),
credential.blinded_serial_number(),
self.nymd_client.address().to_string(),
None,
@@ -91,7 +96,7 @@ impl CoconutVerifier {
self.nymd_client
.grant_allowance(
&api_cosmos_addr,
vec![Coin::new(MAX_FEEGRANT_UNYM, MIX_DENOM.base)],
vec![Coin::new(MAX_FEEGRANT_UNYM, self.mix_denom_base.clone())],
SystemTime::now().checked_add(Duration::from_secs(ONE_HOUR_SEC)),
// It would be nice to be able to filter deeper, but for now only the msg type filter is avaialable
vec![String::from("/cosmwasm.wasm.v1.MsgExecuteContract")],
+4 -2
View File
@@ -9,10 +9,10 @@ use crate::node::client_handling::websocket;
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
use crate::node::statistics::collector::GatewayStatisticsCollector;
use crate::node::storage::Storage;
use config::defaults::DEFAULT_NETWORK;
use crypto::asymmetric::{encryption, identity};
use log::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
use network_defaults::NymNetworkDetails;
use rand::seq::SliceRandom;
use rand::thread_rng;
use statistics_common::collector::StatisticsSender;
@@ -249,7 +249,8 @@ where
.choose(&mut thread_rng())
.expect("The list of validators is empty");
let client_config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
let network_details = NymNetworkDetails::new_from_env();
let client_config = nymd::Config::try_from_nym_network_details(&network_details)
.expect("failed to construct valid validator client config with the provided network");
validator_client::nymd::NymdClient::connect_with_mnemonic(
@@ -316,6 +317,7 @@ where
let coconut_verifier = CoconutVerifier::new(
self.all_api_clients(),
nymd_client,
std::env::var(network_defaults::var_names::MIX_DENOM).expect("mix denom base not set"),
validators_verification_key,
)
.expect("Could not create coconut verifier");
+6 -1
View File
@@ -6,6 +6,7 @@ use std::process;
use crate::{config::Config, Cli};
use clap::Subcommand;
use colored::Colorize;
use config::defaults::var_names::{API_VALIDATOR, BECH32_PREFIX, CONFIGURED};
use crypto::bech32_address_validation;
use url::Url;
@@ -92,6 +93,9 @@ fn override_config(mut config: Config, args: OverrideConfig) -> Config {
if let Some(ref raw_validators) = args.validators {
config = config.with_custom_validator_apis(parse_validators(raw_validators));
} else if std::env::var(CONFIGURED).is_ok() {
let raw_validators = std::env::var(API_VALIDATOR).expect("api validator not set");
config = config.with_custom_validator_apis(parse_validators(&raw_validators))
}
if let Some(ref announce_host) = args.announce_host {
@@ -112,6 +116,7 @@ fn override_config(mut config: Config, args: OverrideConfig) -> Config {
/// Ensures that a given bech32 address is valid, or exits
pub(crate) fn validate_bech32_address_or_exit(address: &str) {
let prefix = std::env::var(BECH32_PREFIX).expect("bech32 prefix not set");
if let Err(bech32_address_validation::Bech32Error::DecodeFailed(err)) =
bech32_address_validation::try_bech32_decode(address)
{
@@ -122,7 +127,7 @@ pub(crate) fn validate_bech32_address_or_exit(address: &str) {
}
if let Err(bech32_address_validation::Bech32Error::WrongPrefix(err)) =
bech32_address_validation::validate_bech32_prefix(address)
bech32_address_validation::validate_bech32_prefix(&prefix, address)
{
let error_message = format!("Error: wallet address type is wrong, {}", err).red();
println!("{}", error_message);
+1 -9
View File
@@ -3,7 +3,6 @@
use crate::config::{missing_string_value, Config};
use clap::Args;
use config::defaults::default_api_endpoints;
use config::NymConfig;
use std::fmt::Display;
use std::process;
@@ -104,14 +103,7 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
let upgraded_config = config
.with_custom_version(to_version.to_string().as_ref())
.with_custom_validator_apis(default_api_endpoints());
let upgraded_config = config.with_custom_version(to_version.to_string().as_ref());
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {:?}", err);
+4 -2
View File
@@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use config::defaults::*;
use config::defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use config::NymConfig;
use serde::{Deserialize, Deserializer, Serialize};
use std::net::{IpAddr, SocketAddr};
@@ -401,7 +403,7 @@ impl Default for MixNode {
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
public_sphinx_key_file: Default::default(),
validator_api_urls: default_api_endpoints(),
validator_api_urls: vec![],
nym_root_directory: Config::default_root_directory(),
wallet_address: "nymXXXXXXXX".to_string(),
}
+7 -6
View File
@@ -4,7 +4,7 @@ extern crate rocket;
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use ::config::defaults::DEFAULT_NETWORK;
use ::config::defaults::setup_env;
use clap::{crate_version, Parser};
use lazy_static::lazy_static;
@@ -24,17 +24,21 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, about, long_version = long_version_static())]
struct Cli {
/// Path pointing to an env file that configures the gateway.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: commands::Commands,
}
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
let args = Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(args).await;
}
@@ -66,7 +70,6 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -83,9 +86,7 @@ fn long_version() -> String {
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
env!("VERGEN_CARGO_PROFILE")
)
}
+4 -7
View File
@@ -680,6 +680,7 @@ name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"multisig-contract-common",
"schemars",
"serde",
]
@@ -805,8 +806,7 @@ dependencies = [
[[package]]
name = "cosmos-sdk-proto"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24ca04d3795c18023c221a2143b29de9c70668ecb22d17783bc02ee780c6c404"
source = "git+https://github.com/neacsu/cosmos-rust?branch=neacsu/feegrant_support#f63ded63ec13e753ebe8bdafe9dc503df265d67d"
dependencies = [
"prost",
"prost-types",
@@ -816,8 +816,7 @@ dependencies = [
[[package]]
name = "cosmrs"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6989fdb6267eccb52762530b79ce0b385f4eaeb8b786522a95512e9bebb268c2"
source = "git+https://github.com/neacsu/cosmos-rust?branch=neacsu/feegrant_support#f63ded63ec13e753ebe8bdafe9dc503df265d67d"
dependencies = [
"bip32",
"cosmos-sdk-proto",
@@ -927,7 +926,6 @@ dependencies = [
"bls12_381",
"coconut-interface",
"crypto",
"network-defaults",
"thiserror",
"url",
"validator-api-requests",
@@ -3273,6 +3271,7 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -3446,7 +3445,6 @@ dependencies = [
"credential-storage",
"crypto",
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
@@ -6485,7 +6483,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
+2 -2
View File
@@ -727,6 +727,7 @@ name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"multisig-contract-common",
"schemars",
"serde",
]
@@ -2790,7 +2791,6 @@ dependencies = [
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
@@ -2887,6 +2887,7 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -5585,7 +5586,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
+1 -1
View File
@@ -78,7 +78,7 @@ pub enum BackendError {
#[error("No balance available for address {0}")]
NoBalance(String),
#[error("The provided network is not supported (yet)")]
NetworkNotSupported(config::defaults::all::Network),
NetworkNotSupported,
#[error("Could not access the local data storage directory")]
UnknownStorageDirectory,
#[error("The wallet file already exists")]
@@ -142,18 +142,16 @@ async fn _connect_with_mnemonic(
)?;
// Set the default account
let default_network: WalletNetwork = config::defaults::DEFAULT_NETWORK.into();
let default_network = WalletNetwork::MAINNET;
let client_for_default_network = clients
.iter()
.find(|client| WalletNetwork::from(client.network.clone()) == default_network);
.find(|(network, _)| *network == default_network);
let account_for_default_network = match client_for_default_network {
Some(client) => Ok(Account::new(
Some((_, client)) => Ok(Account::new(
client.nymd.address().to_string(),
default_network.mix_denom(),
)),
None => Err(BackendError::NetworkNotSupported(
config::defaults::DEFAULT_NETWORK,
)),
None => Err(BackendError::NetworkNotSupported),
};
// Register all the clients
@@ -161,8 +159,7 @@ async fn _connect_with_mnemonic(
let mut w_state = state.write().await;
w_state.logout();
}
for client in clients {
let network: WalletNetwork = client.network.clone().into();
for (network, client) in clients {
let mut w_state = state.write().await;
w_state.add_client(network, client);
w_state.register_default_denoms(network);
@@ -206,7 +203,7 @@ fn create_clients(
default_api_urls: &HashMap<WalletNetwork, Url>,
config: &Config,
mnemonic: &Mnemonic,
) -> Result<Vec<Client<SigningNymdClient>>, BackendError> {
) -> Result<Vec<(WalletNetwork, Client<SigningNymdClient>)>, BackendError> {
let mut clients = Vec::new();
for network in WalletNetwork::iter() {
let nymd_url = if let Some(url) = config.get_selected_validator_nymd_url(network) {
@@ -253,10 +250,9 @@ fn create_clients(
let config = validator_client::Config::try_from_nym_network_details(&network_details)?
.with_urls(nymd_url, api_url);
let mut client =
validator_client::Client::new_signing(config, network.into(), mnemonic.clone())?;
let mut client = validator_client::Client::new_signing(config, mnemonic.clone())?;
client.set_nymd_simulated_gas_multiplier(CUSTOM_SIMULATED_GAS_MULTIPLIER);
clients.push(client);
clients.push((network, client));
}
Ok(clients)
}
@@ -12,7 +12,6 @@ use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
use network_defaults::DEFAULT_NETWORK;
use nymsphinx::addressing::clients::Recipient;
use ordered_buffer::OrderedMessageSender;
use socks5_requests::{ConnectionId, Message as Socks5Message, RemoteAddress, Request};
@@ -59,6 +58,7 @@ pub struct StatsProviderConfigEntry {
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
#[allow(dead_code)]
pub struct OptionalStatsProviderConfig {
mainnet: Option<StatsProviderConfigEntry>,
sandbox: Option<StatsProviderConfigEntry>,
@@ -67,15 +67,7 @@ pub struct OptionalStatsProviderConfig {
impl OptionalStatsProviderConfig {
pub fn stats_client_address(&self) -> Option<String> {
let entry_config = match DEFAULT_NETWORK {
network_defaults::all::Network::MAINNET => self.mainnet.clone(),
network_defaults::all::Network::SANDBOX => self.sandbox.clone(),
network_defaults::all::Network::QA => self.qa.clone(),
network_defaults::all::Network::CUSTOM { .. } => {
panic!("custom network is not supported")
}
};
entry_config.map(|e| e.stats_client_address)
self.mainnet.clone().map(|e| e.stats_client_address)
}
}
+7 -3
View File
@@ -19,7 +19,7 @@ use coconut_bandwidth_contract_common::spend_credential::{
use coconut_interface::{
Attribute, BlindSignRequest, BlindedSignature, KeyPair, Parameters, VerificationKey,
};
use config::defaults::{MIX_DENOM, VALIDATOR_API_VERSION};
use config::defaults::VALIDATOR_API_VERSION;
use credentials::coconut::params::{
ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm,
};
@@ -45,6 +45,7 @@ use self::comm::APICommunicationChannel;
pub struct State {
client: Arc<dyn LocalClient + Send + Sync>,
mix_denom: String,
key_pair: KeyPair,
comm_channel: Arc<dyn APICommunicationChannel + Send + Sync>,
storage: ValidatorApiStorage,
@@ -54,6 +55,7 @@ pub struct State {
impl State {
pub(crate) fn new<C, D>(
client: C,
mix_denom: String,
key_pair: KeyPair,
comm_channel: D,
storage: ValidatorApiStorage,
@@ -67,6 +69,7 @@ impl State {
let rng = Arc::new(Mutex::new(OsRng));
Self {
client,
mix_denom,
key_pair,
comm_channel,
storage,
@@ -160,6 +163,7 @@ impl InternalSignRequest {
pub fn stage<C, D>(
client: C,
mix_denom: String,
key_pair: KeyPair,
comm_channel: D,
storage: ValidatorApiStorage,
@@ -168,7 +172,7 @@ impl InternalSignRequest {
C: LocalClient + Send + Sync + 'static,
D: APICommunicationChannel + Send + Sync + 'static,
{
let state = State::new(client, key_pair, comm_channel, storage);
let state = State::new(client, mix_denom, key_pair, comm_channel, storage);
AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async {
rocket.manage(state).mount(
// this format! is so ugly...
@@ -306,7 +310,7 @@ pub async fn verify_bandwidth_credential(
vote_yes &= Coin::from(proposed_release_funds)
== Coin::new(
verify_credential_body.credential().voucher_value() as u128,
MIX_DENOM.base,
state.mix_denom.clone(),
);
// Vote yes or no on the proposal based on the verification result
+27 -14
View File
@@ -11,7 +11,7 @@ use coconut_bandwidth_contract_common::spend_credential::{
SpendCredential, SpendCredentialResponse,
};
use coconut_interface::{hash_to_scalar, Credential, VerificationKey};
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
use config::defaults::VOUCHER_INFO;
use cosmwasm_std::{to_binary, Addr, CosmosMsg, Decimal, WasmMsg};
use credentials::coconut::bandwidth::BandwidthVoucher;
use credentials::coconut::params::{
@@ -47,6 +47,9 @@ use std::collections::HashMap;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
const TEST_COIN_DENOM: &str = "unym";
const TEST_REWARDING_VALIDATOR_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
#[derive(Clone, Debug)]
struct DummyClient {
validator_address: AccountId,
@@ -178,7 +181,7 @@ async fn check_signer_verif_key(key_pair: KeyPair) {
db_dir.push(&verification_key.to_bs58()[..8]);
let storage = ValidatorApiStorage::init(db_dir).await.unwrap();
let nymd_client = DummyClient::new(
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap(),
AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap(),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
@@ -187,6 +190,7 @@ async fn check_signer_verif_key(key_pair: KeyPair) {
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage,
@@ -271,7 +275,7 @@ async fn signed_before() {
.unwrap()
.insert(tx_hash.to_string(), tx_entry.clone());
let nymd_client = DummyClient::new(
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap(),
AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap(),
&tx_db,
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
@@ -280,6 +284,7 @@ async fn signed_before() {
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage.clone(),
@@ -335,7 +340,7 @@ async fn signed_before() {
#[tokio::test]
async fn state_functions() {
let nymd_client = DummyClient::new(
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap(),
AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap(),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
@@ -346,7 +351,13 @@ async fn state_functions() {
db_dir.push(&key_pair.verification_key().to_bs58()[..8]);
let storage = ValidatorApiStorage::init(db_dir).await.unwrap();
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
let state = State::new(nymd_client, key_pair, comm_channel, storage.clone());
let state = State::new(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage.clone(),
);
let tx_hash = String::from("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E");
assert!(state.signed_before(&tx_hash).await.unwrap().is_none());
@@ -504,7 +515,7 @@ async fn blind_sign_correct() {
.unwrap()
.insert(tx_hash.to_string(), tx_entry.clone());
let nymd_client = DummyClient::new(
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap(),
AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap(),
&tx_db,
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
@@ -513,6 +524,7 @@ async fn blind_sign_correct() {
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage.clone(),
@@ -582,7 +594,7 @@ async fn signature_test() {
db_dir.push(&key_pair.verification_key().to_bs58()[..8]);
let storage = ValidatorApiStorage::init(db_dir).await.unwrap();
let nymd_client = DummyClient::new(
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap(),
AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap(),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
&Arc::new(RwLock::new(HashMap::new())),
@@ -591,6 +603,7 @@ async fn signature_test() {
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage.clone(),
@@ -645,8 +658,7 @@ async fn signature_test() {
#[tokio::test]
async fn get_cosmos_address() {
let validator_address =
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap();
let validator_address = AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap();
let nymd_client = DummyClient::new(
validator_address.clone(),
&Arc::new(RwLock::new(HashMap::new())),
@@ -662,6 +674,7 @@ async fn get_cosmos_address() {
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client,
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel,
storage.clone(),
@@ -687,8 +700,7 @@ async fn get_cosmos_address() {
#[tokio::test]
async fn verification_of_bandwidth_credential() {
// Setup variables
let validator_address =
AccountId::from_str(DEFAULT_NETWORK.rewarding_validator_address()).unwrap();
let validator_address = AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap();
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let spent_credential_db = Arc::new(RwLock::new(HashMap::new()));
let nymd_client = DummyClient::new(
@@ -713,6 +725,7 @@ async fn verification_of_bandwidth_credential() {
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
let rocket = rocket::build().attach(InternalSignRequest::stage(
nymd_client.clone(),
TEST_COIN_DENOM.to_string(),
key_pair,
comm_channel.clone(),
storage1.clone(),
@@ -806,7 +819,7 @@ async fn verification_of_bandwidth_credential() {
);
// Test the endpoint without any credential recorded in the Coconut Bandwidth Contract
let funds = Coin::new(voucher_value as u128, MIX_DENOM.base);
let funds = Coin::new(voucher_value as u128, TEST_COIN_DENOM);
let msg = coconut_bandwidth_contract_common::msg::ExecuteMsg::ReleaseFunds {
funds: funds.clone().into(),
};
@@ -901,7 +914,7 @@ async fn verification_of_bandwidth_credential() {
// Test the endpoint with a proposal that has a different value for the funds to be released
// then what's in the credential
let funds = Coin::new((voucher_value + 10) as u128, MIX_DENOM.base);
let funds = Coin::new((voucher_value + 10) as u128, TEST_COIN_DENOM);
let msg = coconut_bandwidth_contract_common::msg::ExecuteMsg::ReleaseFunds {
funds: funds.clone().into(),
};
@@ -939,7 +952,7 @@ async fn verification_of_bandwidth_credential() {
);
// Test the endpoint with every dependency met
let funds = Coin::new(voucher_value as u128, MIX_DENOM.base);
let funds = Coin::new(voucher_value as u128, TEST_COIN_DENOM);
let msg = coconut_bandwidth_contract_common::msg::ExecuteMsg::ReleaseFunds {
funds: funds.clone().into(),
};
+2 -15
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use config::defaults::DEFAULT_NETWORK;
use config::NymConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
@@ -108,9 +107,7 @@ impl Default for Base {
local_validator: DEFAULT_LOCAL_VALIDATOR
.parse()
.expect("default local validator is malformed!"),
mixnet_contract_address: DEFAULT_NETWORK
.mixnet_contract_address()
.expect("mixnet contract address is unavailable"),
mixnet_contract_address: String::default(),
mnemonic: "exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day".to_string(),
}
}
@@ -279,7 +276,7 @@ impl Default for Rewarding {
}
}
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(default)]
pub struct CoconutSigner {
/// Specifies whether rewarding service is enabled in this process.
@@ -294,16 +291,6 @@ pub struct CoconutSigner {
all_validator_apis: Vec<Url>,
}
impl Default for CoconutSigner {
fn default() -> Self {
CoconutSigner {
enabled: false,
keypair_path: PathBuf::default(),
all_validator_apis: config::defaults::default_api_endpoints(),
}
}
}
impl Config {
pub fn new() -> Self {
Config::default()
+29 -7
View File
@@ -10,7 +10,10 @@ use crate::network_monitor::NetworkMonitorBuilder;
use crate::node_status_api::uptime_updater::HistoricalUptimeUpdater;
use crate::nymd_client::Client;
use crate::storage::ValidatorApiStorage;
use ::config::defaults::DEFAULT_NETWORK;
use ::config::defaults::setup_env;
#[cfg(feature = "coconut")]
use ::config::defaults::var_names::API_VALIDATOR;
use ::config::defaults::var_names::{CONFIGURED, MIXNET_CONTRACT_ADDRESS, MIX_DENOM};
use ::config::NymConfig;
use anyhow::Result;
use clap::{crate_version, App, Arg, ArgMatches};
@@ -23,6 +26,8 @@ use rocket::{Ignite, Rocket};
use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors};
use rocket_okapi::mount_endpoints_and_merged_docs;
use rocket_okapi::swagger_ui::make_swagger_ui;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use std::{fs, process};
@@ -50,6 +55,7 @@ mod swagger;
mod coconut;
const ID: &str = "id";
const CONFIG_ENV_FILE: &str = "config-env-file";
const MONITORING_ENABLED: &str = "enable-monitor";
const REWARDING_ENABLED: &str = "enable-rewarding";
const MIXNET_CONTRACT_ARG: &str = "mixnet-contract";
@@ -98,7 +104,6 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -115,9 +120,7 @@ fn long_version() -> String {
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
env!("VERGEN_CARGO_PROFILE")
)
}
@@ -127,6 +130,12 @@ fn parse_args<'a>() -> ArgMatches<'a> {
.version(crate_version!())
.long_version(&*build_details)
.author("Nymtech")
.arg(
Arg::with_name(CONFIG_ENV_FILE)
.help("Path pointing to an env file that configures the validator API")
.long(CONFIG_ENV_FILE)
.takes_value(true)
)
.arg(
Arg::with_name(ID)
.help("Id of the validator-api we want to run")
@@ -273,6 +282,9 @@ fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
#[cfg(feature = "coconut")]
if let Some(raw_validators) = matches.value_of(API_VALIDATORS_ARG) {
config = config.with_custom_validator_apis(parse_validators(raw_validators));
} else if std::env::var(CONFIGURED).is_ok() {
let raw_validators = std::env::var(API_VALIDATOR).expect("api validator not set");
config = config.with_custom_validator_apis(parse_validators(&raw_validators))
}
if let Some(raw_validator) = matches.value_of(NYMD_VALIDATOR_ARG) {
@@ -288,6 +300,10 @@ fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
if let Some(mixnet_contract) = matches.value_of(MIXNET_CONTRACT_ARG) {
config = config.with_custom_mixnet_contract(mixnet_contract)
} else if std::env::var(CONFIGURED).is_ok() {
let mixnet_contract =
std::env::var(MIXNET_CONTRACT_ADDRESS).expect("mixnet contract not set");
config = config.with_custom_mixnet_contract(mixnet_contract)
}
if let Some(mnemonic) = matches.value_of(MNEMONIC_ARG) {
@@ -413,6 +429,7 @@ fn expected_monitor_test_runs(config: &Config, interval_length: Duration) -> usi
async fn setup_rocket(
config: &Config,
_mix_denom: String,
liftoff_notify: Arc<Notify>,
_nymd_client: Client<SigningNymdClient>,
) -> Result<Rocket<Ignite>> {
@@ -452,6 +469,7 @@ async fn setup_rocket(
let keypair = KeyPair::try_from_bs58(keypair_bs58)?;
rocket.attach(InternalSignRequest::stage(
_nymd_client,
_mix_denom,
keypair,
QueryCommunicationChannel::new(config.get_all_validator_api_endpoints()),
storage.clone().unwrap(),
@@ -524,6 +542,7 @@ async fn run_validator_api(matches: ArgMatches<'static>) -> Result<()> {
if matches.is_present(WRITE_CONFIG_ARG) {
return Ok(());
}
let mix_denom = std::env::var(MIX_DENOM).expect("mix denom not set");
let signing_nymd_client = Client::new_signing(&config);
@@ -532,6 +551,7 @@ async fn run_validator_api(matches: ArgMatches<'static>) -> Result<()> {
// let's build our rocket!
let rocket = setup_rocket(
&config,
mix_denom,
Arc::clone(&liftoff_notify),
signing_nymd_client.clone(),
)
@@ -605,8 +625,6 @@ async fn run_validator_api(matches: ArgMatches<'static>) -> Result<()> {
async fn main() -> Result<()> {
println!("Starting validator api...");
let _ = dotenv::dotenv();
cfg_if::cfg_if! {if #[cfg(feature = "console-subscriber")] {
// instriment tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
console_subscriber::init();
@@ -614,5 +632,9 @@ async fn main() -> Result<()> {
setup_logging();
let args = parse_args();
let config_env_file = args
.value_of(CONFIG_ENV_FILE)
.map(|s| PathBuf::from_str(s).expect("invalid env config file"));
setup_env(config_env_file);
run_validator_api(args).await
}
+7 -10
View File
@@ -11,7 +11,7 @@ use std::time::Duration;
use tokio::sync::RwLock;
use tokio::time::sleep;
use config::defaults::{DEFAULT_NETWORK, DEFAULT_VALIDATOR_API_PORT};
use config::defaults::{NymNetworkDetails, DEFAULT_VALIDATOR_API_PORT};
use mixnet_contract_common::{
reward_params::EpochRewardParams, ContractStateParams, Delegation, ExecuteMsg, GatewayBond,
IdentityKey, Interval, MixNodeBond, MixnodeRewardingStatusResponse, RewardedSetNodeStatus,
@@ -51,17 +51,16 @@ impl Client<QueryNymdClient> {
.parse()
.unwrap();
let nymd_url = config.get_nymd_validator_url();
let network = DEFAULT_NETWORK;
let details = network
.details()
let details = NymNetworkDetails::new_from_env()
.with_mixnet_contract(Some(config.get_mixnet_contract_address()));
let client_config = validator_client::Config::try_from_nym_network_details(&details)
.expect("failed to construct valid validator client config with the provided network")
.with_urls(nymd_url, api_url);
let inner = validator_client::Client::new_query(client_config, network)
.expect("Failed to connect to nymd!");
let inner =
validator_client::Client::new_query(client_config).expect("Failed to connect to nymd!");
Client(Arc::new(RwLock::new(inner)))
}
@@ -76,9 +75,7 @@ impl Client<SigningNymdClient> {
.unwrap();
let nymd_url = config.get_nymd_validator_url();
let network = DEFAULT_NETWORK;
let details = network
.details()
let details = NymNetworkDetails::new_from_env()
.with_mixnet_contract(Some(config.get_mixnet_contract_address()));
let client_config = validator_client::Config::try_from_nym_network_details(&details)
@@ -90,7 +87,7 @@ impl Client<SigningNymdClient> {
.parse()
.expect("the mnemonic is invalid!");
let inner = validator_client::Client::new_signing(client_config, network, mnemonic)
let inner = validator_client::Client::new_signing(client_config, mnemonic)
.expect("Failed to connect to nymd!");
Client(Arc::new(RwLock::new(inner)))