Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 40 additions & 5 deletions common/commands/src/validator/cosmwasm/generators/mixnet.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
// Copyright 2022 - Nym Technologies SA <[email protected]>
// Copyright 2022-2024 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use clap::Parser;
use log::{debug, info};

use cosmwasm_std::Decimal;
use nym_mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
use nym_validator_client::nyxd::AccountId;
use log::{debug, info};
use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
};
use nym_network_defaults::mainnet::MIX_DENOM;
use nym_network_defaults::TOTAL_SUPPLY;
use nym_validator_client::nyxd::{AccountId, Coin};
use std::str::FromStr;
use std::time::Duration;

pub fn default_maximum_operating_cost() -> Coin {
Coin::new(TOTAL_SUPPLY, MIX_DENOM.base)
}

pub fn default_minimum_operating_cost() -> Coin {
Coin::new(0, MIX_DENOM.base)
}

#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
Expand Down Expand Up @@ -50,6 +61,18 @@ pub struct Args {

#[clap(long, default_value_t = 240)]
pub active_set_size: u32,

#[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent,

#[clap(long, default_value_t = Percent::hundred())]
pub maximum_profit_margin_percent: Percent,

#[clap(long, default_value_t = default_minimum_operating_cost())]
pub minimum_interval_operating_cost: Coin,

#[clap(long, default_value_t = default_maximum_operating_cost())]
pub maximum_interval_operating_cost: Coin,
}

pub async fn generate(args: Args) {
Expand Down Expand Up @@ -97,13 +120,25 @@ pub async fn generate(args: Args) {
.expect("Rewarding (mix) denom has to be set")
});

if args.minimum_interval_operating_cost.denom != args.maximum_interval_operating_cost.denom {
panic!("different denoms for operating cost bounds")
}

let instantiate_msg = InstantiateMsg {
rewarding_validator_address: rewarding_validator_address.to_string(),
vesting_contract_address: vesting_contract_address.to_string(),
rewarding_denom,
epochs_in_interval: args.epochs_in_interval,
epoch_duration: Duration::from_secs(args.epoch_duration),
initial_rewarding_params,
profit_margin: ProfitMarginRange {
minimum: args.minimum_profit_margin_percent,
maximum: args.maximum_profit_margin_percent,
},
interval_operating_cost: OperatingCostRange {
minimum: args.minimum_interval_operating_cost.amount.into(),
maximum: args.maximum_interval_operating_cost.amount.into(),
},
};

debug!("instantiate_msg: {:?}", instantiate_msg);
Expand Down
16 changes: 15 additions & 1 deletion common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright 2022-2023 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use crate::{EpochEventId, EpochState, IdentityKey, MixId};
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
use contracts_common::signing::verifier::ApiVerifierError;
use contracts_common::Percent;
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
use thiserror::Error;

Expand Down Expand Up @@ -239,6 +240,19 @@ pub enum MixnetContractError {
#[from]
source: ApiVerifierError,
},

#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
ProfitMarginOutsideRange {
provided: Percent,
range: ProfitMarginRange,
},

#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
OperatingCostOutsideRange {
denom: String,
provided: Uint128,
range: OperatingCostRange,
},
}

impl MixnetContractError {
Expand Down
15 changes: 14 additions & 1 deletion common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use crate::helpers::IntoBaseDecimal;
use crate::reward_params::{NodeRewardParams, RewardingParams};
use crate::rewarding::helpers::truncate_reward;
use crate::rewarding::RewardDistribution;
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
use crate::{
Delegation, EpochEventId, EpochId, IdentityKey, MixId, OperatingCostRange, Percent,
ProfitMarginRange, SphinxKey,
};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
use schemars::JsonSchema;
Expand Down Expand Up @@ -152,6 +155,16 @@ impl MixNodeRewarding {
})
}

pub fn normalise_profit_margin(&mut self, allowed_range: ProfitMarginRange) {
self.cost_params.profit_margin_percent =
allowed_range.normalise(self.cost_params.profit_margin_percent)
}

pub fn normalise_operating_cost(&mut self, allowed_range: OperatingCostRange) {
self.cost_params.interval_operating_cost.amount =
allowed_range.normalise(self.cost_params.interval_operating_cost.amount)
}

/// Determines whether this node is still bonded. This is performed via a simple check,
/// if there are no tokens left associated with the operator, it means they have unbonded
/// and those params only exist for the purposes of calculating rewards for delegators that
Expand Down
9 changes: 8 additions & 1 deletion common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <[email protected]>
// Copyright 2021-2024 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use crate::delegation::{self, OwnerProxySubKey};
Expand All @@ -12,6 +12,7 @@ use crate::reward_params::{
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
};
use crate::types::{ContractStateParams, LayerAssignment, MixId};
use crate::{OperatingCostRange, ProfitMarginRange};
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal};
Expand Down Expand Up @@ -57,6 +58,12 @@ pub struct InstantiateMsg {
pub epochs_in_interval: u32,
pub epoch_duration: Duration,
pub initial_rewarding_params: InitialRewardingParams,

#[serde(default)]
pub profit_margin: ProfitMarginRange,

#[serde(default)]
pub interval_operating_cost: OperatingCostRange,
}

#[cw_serde]
Expand Down
73 changes: 72 additions & 1 deletion common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

use crate::error::MixnetContractError;
use crate::Layer;
use contracts_common::Percent;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use cosmwasm_std::Coin;
use cosmwasm_std::{Addr, Uint128};
use std::fmt::{Display, Formatter};
use std::ops::Index;

// type aliases for better reasoning about available data
Expand All @@ -15,6 +17,65 @@ pub type SphinxKeyRef<'a> = &'a str;
pub type MixId = u32;
pub type BlockHeight = u64;

#[cw_serde]
pub struct RangedValue<T> {
pub minimum: T,
pub maximum: T,
}

impl<T> Copy for RangedValue<T> where T: Copy {}

pub type ProfitMarginRange = RangedValue<Percent>;
pub type OperatingCostRange = RangedValue<Uint128>;

impl<T> Display for RangedValue<T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} - {}", self.minimum, self.maximum)
}
}

impl Default for ProfitMarginRange {
fn default() -> Self {
ProfitMarginRange {
minimum: Percent::zero(),
maximum: Percent::hundred(),
}
}
}

impl Default for OperatingCostRange {
fn default() -> Self {
OperatingCostRange {
minimum: Uint128::zero(),

// 1 billion (native tokens, i.e. 1 billion * 1'000'000 base tokens) - the total supply
maximum: Uint128::new(1_000_000_000_000_000),
}
}
}

impl<T> RangedValue<T>
where
T: Copy + PartialOrd + PartialEq,
{
pub fn normalise(&self, value: T) -> T {
if value < self.minimum {
self.minimum
} else if value > self.maximum {
self.maximum
} else {
value
}
}

pub fn within_range(&self, value: T) -> bool {
value >= self.minimum && value <= self.maximum
}
}

/// Specifies layer assignment for the given mixnode.
#[cw_serde]
pub struct LayerAssignment {
Expand Down Expand Up @@ -154,4 +215,14 @@ pub struct ContractStateParams {

/// Minimum amount a gateway must pledge to get into the system.
pub minimum_gateway_pledge: Coin,

/// Defines the allowed profit margin range of operators.
/// default: 0% - 100%
#[serde(default)]
pub profit_margin: ProfitMarginRange,

/// Defines the allowed interval operating cost range of operators.
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
#[serde(default)]
pub interval_operating_cost: OperatingCostRange,
}
4 changes: 4 additions & 0 deletions common/types/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use nym_mixnet_contract_common::ContractsCommonError;
use nym_validator_client::error::TendermintRpcError;
use nym_validator_client::nym_api::error::NymAPIError;
use nym_validator_client::{nyxd::error::NyxdError, ValidatorClientError};
Expand All @@ -8,6 +9,9 @@ use thiserror::Error;
// TODO: ask @MS why this even exists
#[derive(Error, Debug)]
pub enum TypesError {
#[error(transparent)]
ContractsCommon(#[from] ContractsCommonError),

#[error("{source}")]
NyxdError {
#[from]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ pub fn default_mixnet_init_msg() -> nym_mixnet_contract_common::InstantiateMsg {
rewarded_set_size: 240,
active_set_size: 100,
},
profit_margin: Default::default(),
interval_operating_cost: Default::default(),
}
}
Loading