No more floats
[ci skip] Generate TS types
This commit is contained in:
Generated
+5
-52
@@ -1431,7 +1431,7 @@ checksum = "ecf692a2ee5c5f699ed0e95f21686cf6367f3a591e5d8e7bd3041bbf184651f9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fnv",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecmascript",
|
||||
@@ -3048,7 +3048,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"num",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
@@ -3216,20 +3215,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||
dependencies = [
|
||||
"num-bigint 0.4.2",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
@@ -3242,26 +3227,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
@@ -3294,18 +3259,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-bigint 0.4.2",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
@@ -5838,7 +5791,7 @@ dependencies = [
|
||||
"from_variant",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"owning_ref",
|
||||
"scoped-tls",
|
||||
@@ -5856,7 +5809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83eb6a73820660a5af3c24ae1d436e84e4d4c13822021140011361e678df247b"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"string_enum",
|
||||
"swc_atoms",
|
||||
@@ -5873,7 +5826,7 @@ dependencies = [
|
||||
"enum_kind",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"smallvec 1.6.1",
|
||||
"swc_atoms",
|
||||
@@ -5889,7 +5842,7 @@ version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3d60b9dc97ae4f181d4d60f43142d8ac9669953db410bcedefb29a14627e19"
|
||||
dependencies = [
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
|
||||
@@ -15,7 +15,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
schemars = "0.8"
|
||||
ts-rs = { version = "3.0", optional = true }
|
||||
num = "0.4.0"
|
||||
thiserror = "1.0"
|
||||
config = { path = "../config" }
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum MixnetContractError {
|
||||
#[error("Could not convert ration to f64: {0} / {1}")]
|
||||
InvalidRatio(u128, u128),
|
||||
#[error("Overflow Error")]
|
||||
OverflowError (#[from] cosmwasm_std::OverflowError),
|
||||
#[error("reward_blockstamp field not set, set_reward_blockstamp must be called before attempting to issue rewards")]
|
||||
BlockstampNotSet,
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::{IdentityKey, SphinxKey};
|
||||
use config::defaults::{ALPHA, DEFAULT_OPERATOR_EPOCH_COST};
|
||||
use cosmwasm_std::{coin, Addr, Coin, Uint128};
|
||||
use num::rational::Ratio;
|
||||
use num::ToPrimitive;
|
||||
use cosmwasm_std::{coin, Addr, Coin, Decimal, Fraction, Uint128};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
@@ -15,7 +13,24 @@ use std::fmt::Display;
|
||||
|
||||
use crate::current_block_height;
|
||||
|
||||
const DEFAULT_PROFIT_MARGIN: f64 = 0.1;
|
||||
const DEFAULT_PROFIT_MARGIN: u8 = 10; // expressed as percent
|
||||
|
||||
const DECIMAL_FRACTIONAL: Uint128 = Uint128(1_000_000_000_000_000_000u128);
|
||||
|
||||
fn mul_fraction(lhs: Decimal, rhs: Decimal) -> Decimal {
|
||||
Decimal::from_ratio(
|
||||
lhs.numerator() * rhs.numerator(),
|
||||
lhs.denominator() * rhs.denominator(),
|
||||
)
|
||||
}
|
||||
|
||||
fn decimal_to_uint128(value: Decimal) -> Uint128 {
|
||||
value * DECIMAL_FRACTIONAL
|
||||
}
|
||||
|
||||
fn uint128_to_decimal(value: Uint128) -> Decimal {
|
||||
Decimal::from_ratio(value, DECIMAL_FRACTIONAL)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
@@ -43,57 +58,74 @@ pub enum Layer {
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct NodeRewardParams {
|
||||
income_global_mix: f64,
|
||||
k: f64,
|
||||
one_over_k: f64,
|
||||
performance: f64,
|
||||
income_global_mix: Uint128,
|
||||
k: Uint128,
|
||||
one_over_k: Decimal,
|
||||
total_epoch_uptime: u128,
|
||||
reward_blockstamp: Option<u64>,
|
||||
total_mix_stake: Uint128,
|
||||
uptime: f64,
|
||||
uptime: Decimal,
|
||||
}
|
||||
|
||||
impl NodeRewardParams {
|
||||
pub fn new(
|
||||
income_global_mix: f64,
|
||||
k: f64,
|
||||
performance: f64,
|
||||
income_global_mix: u128,
|
||||
k: u128,
|
||||
total_epoch_uptime: u128,
|
||||
reward_blockstamp: Option<u64>,
|
||||
total_mix_stake: u128,
|
||||
uptime: f64,
|
||||
uptime: u8,
|
||||
) -> NodeRewardParams {
|
||||
let k = Uint128(k);
|
||||
NodeRewardParams {
|
||||
income_global_mix,
|
||||
income_global_mix: Uint128(income_global_mix),
|
||||
k,
|
||||
one_over_k: 1. / k,
|
||||
performance,
|
||||
one_over_k: Decimal::one() / k,
|
||||
total_epoch_uptime,
|
||||
reward_blockstamp,
|
||||
total_mix_stake: Uint128(total_mix_stake),
|
||||
uptime,
|
||||
uptime: Decimal::percent(uptime.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operator_cost(&self) -> f64 {
|
||||
self.uptime / 100. * DEFAULT_OPERATOR_EPOCH_COST as f64
|
||||
pub fn performance(&self) -> Decimal {
|
||||
Decimal::from_ratio(decimal_to_uint128(self.uptime), self.total_epoch_uptime)
|
||||
}
|
||||
|
||||
pub fn operator_cost(&self) -> Uint128 {
|
||||
self.uptime * Uint128(DEFAULT_OPERATOR_EPOCH_COST.into())
|
||||
}
|
||||
|
||||
pub fn operator_cost_decimal(&self) -> Decimal {
|
||||
uint128_to_decimal(self.operator_cost())
|
||||
}
|
||||
|
||||
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
|
||||
self.reward_blockstamp = Some(blockstamp);
|
||||
}
|
||||
|
||||
pub fn alpha(&self) -> f64 {
|
||||
ALPHA
|
||||
pub fn alpha_decimal(&self) -> Decimal {
|
||||
Decimal::percent(ALPHA.into())
|
||||
}
|
||||
|
||||
pub fn income_global_mix(&self) -> f64 {
|
||||
pub fn alpha(&self) -> Uint128 {
|
||||
decimal_to_uint128(self.alpha_decimal())
|
||||
}
|
||||
|
||||
pub fn income_global_mix(&self) -> Uint128 {
|
||||
self.income_global_mix
|
||||
}
|
||||
|
||||
pub fn k(&self) -> f64 {
|
||||
pub fn income_global_mix_decimal(&self) -> Decimal {
|
||||
Decimal::from_ratio(self.income_global_mix, 1u128)
|
||||
}
|
||||
|
||||
pub fn k(&self) -> Uint128 {
|
||||
self.k
|
||||
}
|
||||
|
||||
pub fn performance(&self) -> f64 {
|
||||
self.performance
|
||||
pub fn k_decimal(&self) -> Decimal {
|
||||
uint128_to_decimal(self.k)
|
||||
}
|
||||
|
||||
pub fn total_mix_stake(&self) -> Uint128 {
|
||||
@@ -105,28 +137,28 @@ impl NodeRewardParams {
|
||||
.ok_or(MixnetContractError::BlockstampNotSet)
|
||||
}
|
||||
|
||||
pub fn one_over_k(&self) -> f64 {
|
||||
pub fn one_over_k(&self) -> Decimal {
|
||||
self.one_over_k
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NodeRewardResult {
|
||||
reward: f64,
|
||||
lambda: f64,
|
||||
sigma: f64,
|
||||
reward: Decimal,
|
||||
lambda: Decimal,
|
||||
sigma: Decimal,
|
||||
}
|
||||
|
||||
impl NodeRewardResult {
|
||||
pub fn reward(&self) -> f64 {
|
||||
pub fn reward(&self) -> Decimal {
|
||||
self.reward
|
||||
}
|
||||
|
||||
pub fn lambda(&self) -> f64 {
|
||||
pub fn lambda(&self) -> Decimal {
|
||||
self.lambda
|
||||
}
|
||||
|
||||
pub fn sigma(&self) -> f64 {
|
||||
pub fn sigma(&self) -> Decimal {
|
||||
self.sigma
|
||||
}
|
||||
}
|
||||
@@ -140,7 +172,7 @@ pub struct MixNodeBond {
|
||||
#[serde(default = "current_block_height")]
|
||||
pub block_height: u64,
|
||||
pub mix_node: MixNode,
|
||||
pub profit_margin: Option<f64>,
|
||||
pub profit_margin_percent: Option<u8>,
|
||||
}
|
||||
|
||||
impl MixNodeBond {
|
||||
@@ -150,7 +182,7 @@ impl MixNodeBond {
|
||||
layer: Layer,
|
||||
block_height: u64,
|
||||
mix_node: MixNode,
|
||||
profit_margin: Option<f64>,
|
||||
profit_margin_percent: Option<u8>,
|
||||
) -> Self {
|
||||
MixNodeBond {
|
||||
total_delegation: coin(0, &bond_amount.denom),
|
||||
@@ -159,18 +191,22 @@ impl MixNodeBond {
|
||||
layer,
|
||||
block_height,
|
||||
mix_node,
|
||||
profit_margin,
|
||||
profit_margin_percent,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn profit_margin(&self) -> f64 {
|
||||
if let Some(margin) = self.profit_margin {
|
||||
margin
|
||||
pub fn profit_margin_decimal(&self) -> Decimal {
|
||||
if let Some(margin) = self.profit_margin_percent {
|
||||
Decimal::percent(margin.into())
|
||||
} else {
|
||||
DEFAULT_PROFIT_MARGIN
|
||||
Decimal::percent(DEFAULT_PROFIT_MARGIN.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn profit_margin(&self) -> Uint128 {
|
||||
decimal_to_uint128(self.profit_margin_decimal())
|
||||
}
|
||||
|
||||
pub fn identity(&self) -> &String {
|
||||
&self.mix_node.identity_key
|
||||
}
|
||||
@@ -191,55 +227,25 @@ impl MixNodeBond {
|
||||
self.total_delegation.clone()
|
||||
}
|
||||
|
||||
pub fn bond_to_total_stake_ratio(&self, total_stake: Uint128) -> Ratio<u128> {
|
||||
Ratio::new(self.bond_amount().amount.u128(), total_stake.u128())
|
||||
pub fn bond_to_total_stake(&self, total_stake: Uint128) -> Decimal {
|
||||
Decimal::from_ratio(self.bond_amount().amount, total_stake)
|
||||
}
|
||||
|
||||
pub fn bond_to_total_stake_f64(
|
||||
&self,
|
||||
total_stake: Uint128,
|
||||
) -> Result<f64, MixnetContractError> {
|
||||
let ratio = self.bond_to_total_stake_ratio(total_stake);
|
||||
if let Some(f) = ratio.to_f64() {
|
||||
Ok(f)
|
||||
} else {
|
||||
Err(MixnetContractError::InvalidRatio(
|
||||
*ratio.numer(),
|
||||
*ratio.denom(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stake_to_total_stake_ratio(&self, total_stake: Uint128) -> Ratio<u128> {
|
||||
Ratio::new(
|
||||
self.bond_amount().amount.u128() + self.total_delegation().amount.u128(),
|
||||
total_stake.u128(),
|
||||
pub fn stake_to_total_stake(&self, total_stake: Uint128) -> Decimal {
|
||||
Decimal::from_ratio(
|
||||
self.bond_amount().amount + self.total_delegation().amount,
|
||||
total_stake,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn stake_to_total_stake_f64(
|
||||
&self,
|
||||
total_stake: Uint128,
|
||||
) -> Result<f64, MixnetContractError> {
|
||||
let ratio = self.stake_to_total_stake_ratio(total_stake);
|
||||
if let Some(f) = ratio.to_f64() {
|
||||
Ok(f)
|
||||
} else {
|
||||
Err(MixnetContractError::InvalidRatio(
|
||||
*ratio.numer(),
|
||||
*ratio.denom(),
|
||||
))
|
||||
}
|
||||
pub fn lambda(&self, params: &NodeRewardParams) -> Decimal {
|
||||
let bond_to_total_stake_ratio = self.bond_to_total_stake(params.total_mix_stake);
|
||||
bond_to_total_stake_ratio.min(params.one_over_k)
|
||||
}
|
||||
|
||||
pub fn lambda(&self, params: &NodeRewardParams) -> Result<f64, MixnetContractError> {
|
||||
let bond_to_total_stake_ratio = self.bond_to_total_stake_f64(params.total_mix_stake)?;
|
||||
Ok(bond_to_total_stake_ratio.min(params.one_over_k))
|
||||
}
|
||||
|
||||
pub fn sigma(&self, params: &NodeRewardParams) -> Result<f64, MixnetContractError> {
|
||||
let stake_to_total_stake_ratio = self.stake_to_total_stake_f64(params.total_mix_stake)?;
|
||||
Ok(stake_to_total_stake_ratio.min(params.one_over_k))
|
||||
pub fn sigma(&self, params: &NodeRewardParams) -> Decimal {
|
||||
let stake_to_total_stake_ratio = self.stake_to_total_stake(params.total_mix_stake);
|
||||
stake_to_total_stake_ratio.min(params.one_over_k)
|
||||
}
|
||||
|
||||
pub fn reward(
|
||||
@@ -247,39 +253,55 @@ impl MixNodeBond {
|
||||
params: &NodeRewardParams,
|
||||
) -> Result<NodeRewardResult, MixnetContractError> {
|
||||
// Assuming uniform work distribution across the network this is one_over_k * k
|
||||
let omega_k = 1.;
|
||||
let lambda = self.lambda(params)?;
|
||||
let sigma = self.sigma(params)?;
|
||||
let reward = params.performance
|
||||
* params.income_global_mix
|
||||
* (sigma * omega_k + params.alpha() * lambda * (sigma * params.k))
|
||||
/ (1. + params.alpha());
|
||||
let omega_k = Decimal::one();
|
||||
let lambda = self.lambda(params);
|
||||
let sigma = self.sigma(params);
|
||||
println!("{}", params.performance());
|
||||
println!("{}", params.income_global_mix_decimal());
|
||||
let income_fraction = mul_fraction(params.performance(), params.income_global_mix_decimal());
|
||||
let sigma_x_omega = mul_fraction(sigma, omega_k);
|
||||
let sigma_x_k = mul_fraction(sigma, params.k_decimal());
|
||||
let params_x_alpha = mul_fraction(params.alpha_decimal(), lambda);
|
||||
let after_plus_parens = mul_fraction(sigma_x_k,params_x_alpha);
|
||||
let plus_in_parens = sigma_x_omega + after_plus_parens;
|
||||
let numer = mul_fraction(income_fraction, plus_in_parens);
|
||||
let denom = Decimal::one() + params.alpha_decimal();
|
||||
let reward = Decimal::from_ratio(
|
||||
numer.numerator() * denom.denominator(),
|
||||
numer.denominator() * denom.numerator(),
|
||||
);
|
||||
|
||||
Ok(NodeRewardResult {
|
||||
reward,
|
||||
lambda,
|
||||
sigma,
|
||||
lambda: lambda,
|
||||
sigma: sigma,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn node_profit(&self, params: &NodeRewardParams) -> Result<f64, MixnetContractError> {
|
||||
Ok(self.reward(params)?.reward() - params.operator_cost())
|
||||
pub fn node_profit(&self, params: &NodeRewardParams) -> Result<Decimal, MixnetContractError> {
|
||||
Ok(self.reward(params)?.reward() - params.operator_cost_decimal())
|
||||
}
|
||||
|
||||
pub fn operator_profit(&self, params: &NodeRewardParams) -> Result<f64, MixnetContractError> {
|
||||
pub fn operator_profit(
|
||||
&self,
|
||||
params: &NodeRewardParams,
|
||||
) -> Result<Decimal, MixnetContractError> {
|
||||
let reward_result = self.reward(params)?;
|
||||
let profit = reward_result.reward() - params.operator_cost();
|
||||
Ok(((self.profit_margin()
|
||||
+ (1. - self.profit_margin()) * (reward_result.lambda() / reward_result.sigma()))
|
||||
* profit)
|
||||
.max(0.))
|
||||
let profit = reward_result.reward() - params.operator_cost_decimal();
|
||||
let lambda_over_sigma =
|
||||
decimal_to_uint128(reward_result.lambda() / decimal_to_uint128(reward_result.sigma()));
|
||||
let one_minus_margin = Decimal::one() - self.profit_margin_decimal();
|
||||
let one_minus_times_lambda_over_sigma = one_minus_margin * lambda_over_sigma;
|
||||
let left_side = self.profit_margin() + one_minus_times_lambda_over_sigma;
|
||||
let operator_reward = uint128_to_decimal(left_side * profit);
|
||||
Ok(operator_reward.max(Decimal::zero()))
|
||||
}
|
||||
|
||||
pub fn sigma_ratio(&self, params: &NodeRewardParams) -> Result<f64, MixnetContractError> {
|
||||
if self.stake_to_total_stake_f64(params.total_mix_stake)? < params.one_over_k {
|
||||
self.stake_to_total_stake_f64(params.total_mix_stake)
|
||||
pub fn sigma_ratio(&self, params: &NodeRewardParams) -> Decimal {
|
||||
if self.stake_to_total_stake(params.total_mix_stake) < params.one_over_k {
|
||||
self.stake_to_total_stake(params.total_mix_stake)
|
||||
} else {
|
||||
Ok(params.one_over_k)
|
||||
params.one_over_k
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,23 +309,20 @@ impl MixNodeBond {
|
||||
&self,
|
||||
delegation_amount: Uint128,
|
||||
params: &NodeRewardParams,
|
||||
) -> Result<Uint128, MixnetContractError> {
|
||||
) -> Result<Decimal, MixnetContractError> {
|
||||
let scaled_delegation_amount =
|
||||
Ratio::new(delegation_amount.u128(), params.total_mix_stake.u128())
|
||||
.to_f64()
|
||||
.ok_or_else(|| {
|
||||
MixnetContractError::InvalidRatio(
|
||||
delegation_amount.u128(),
|
||||
params.total_mix_stake.u128(),
|
||||
)
|
||||
})?;
|
||||
Decimal::from_ratio(delegation_amount, params.total_mix_stake);
|
||||
|
||||
let delegation_over_sigma_f64 = scaled_delegation_amount / self.sigma(params)?;
|
||||
// If we can't resolve the ration we move on, and the delegation does not get rewarded
|
||||
Ok(Uint128(
|
||||
((1. - self.profit_margin()) * delegation_over_sigma_f64 * self.node_profit(params)?)
|
||||
.max(0.) as u128,
|
||||
))
|
||||
let delegation_over_sigma =
|
||||
scaled_delegation_amount / decimal_to_uint128(self.sigma(params));
|
||||
|
||||
let one_minus_profit = Decimal::one() - self.profit_margin_decimal();
|
||||
let times_delegation_over_sigma =
|
||||
one_minus_profit * decimal_to_uint128(delegation_over_sigma);
|
||||
let delegation_reward =
|
||||
uint128_to_decimal(times_delegation_over_sigma * self.node_profit(params)?);
|
||||
|
||||
Ok(delegation_reward.max(Decimal::zero()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +455,7 @@ mod tests {
|
||||
layer: Layer::One,
|
||||
block_height: 100,
|
||||
mix_node: mixnode_fixture(),
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
let mix2 = MixNodeBond {
|
||||
@@ -446,7 +465,7 @@ mod tests {
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
let mix3 = MixNodeBond {
|
||||
@@ -456,7 +475,7 @@ mod tests {
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
let mix4 = MixNodeBond {
|
||||
@@ -466,7 +485,7 @@ mod tests {
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
let mix5 = MixNodeBond {
|
||||
@@ -476,7 +495,7 @@ mod tests {
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
// summary:
|
||||
|
||||
@@ -96,5 +96,5 @@ pub const DEFAULT_FIRST_EPOCH_START: OffsetDateTime = time::macros::datetime!(20
|
||||
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60); // 24h
|
||||
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate epoch costs to Nyms. We'll also assume a cost of 40$ per epoch(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
|
||||
pub const DEFAULT_OPERATOR_EPOCH_COST: u64 = 1333333; // 40$ a month at 1 Nym == 1$
|
||||
// Sybil attack resistance parameter
|
||||
pub const ALPHA: f64 = 0.3;
|
||||
|
||||
pub const ALPHA: u8 = 30; // Sybil attack resistance parameter expressed as percent
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.envrc
|
||||
Generated
-1
@@ -640,7 +640,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"num",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
|
||||
|
||||
upload: wasm
|
||||
validator-client-scripts --nymd-url ${QA_NYMD_URL} --mnemonic "${QA_MNEMONIC}" upload --memo 'Uploading mixnet contract to QAnet' --wasm-path target/wasm32-unknown-unknown/release/mixnet_contracts.wasm
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
@@ -19,11 +19,11 @@ const DECIMAL_FRACTIONAL: Uint128 = Uint128(1_000_000_000_000_000_000u128);
|
||||
// cosmwasm bucket internal value
|
||||
const NAMESPACE_LENGTH: usize = 2;
|
||||
|
||||
fn decimal_to_uint128(value: Decimal) -> Uint128 {
|
||||
pub fn decimal_to_uint128(value: Decimal) -> Uint128 {
|
||||
value * DECIMAL_FRACTIONAL
|
||||
}
|
||||
|
||||
fn uint128_to_decimal(value: Uint128) -> Decimal {
|
||||
pub fn uint128_to_decimal(value: Uint128) -> Decimal {
|
||||
Decimal::from_ratio(value, DECIMAL_FRACTIONAL)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use mixnet_contract::{
|
||||
use mixnet_contract::mixnode::NodeRewardParams;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use crate::helpers::decimal_to_uint128;
|
||||
|
||||
// storage prefixes
|
||||
// all of them must be unique and presumably not be a prefix of a different one
|
||||
@@ -357,7 +358,7 @@ pub(crate) fn increase_mix_delegated_stakes_v2(
|
||||
// since they delegated
|
||||
for (delegator_address, mut delegation) in delegations_chunk.into_iter() {
|
||||
if delegation.block_height + MINIMUM_BLOCK_AGE_FOR_REWARDING <= params.reward_blockstamp()? {
|
||||
let reward = bond.reward_delegation(delegation.amount, params)?;
|
||||
let reward = decimal_to_uint128(bond.reward_delegation(delegation.amount, params)?);
|
||||
delegation.amount += reward;
|
||||
total_rewarded += reward;
|
||||
mix_delegations(storage, bond.identity()).save(&delegator_address, &delegation)?;
|
||||
@@ -625,7 +626,7 @@ mod tests {
|
||||
identity_key: node_identity.clone(),
|
||||
..mix_node_fixture()
|
||||
},
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
mixnodes(&mut storage)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use crate::error::ContractError;
|
||||
use crate::helpers::{calculate_epoch_reward_rate, scale_reward_by_uptime, Delegations};
|
||||
use crate::helpers::{calculate_epoch_reward_rate, scale_reward_by_uptime, Delegations, decimal_to_uint128};
|
||||
use crate::queries;
|
||||
use crate::storage::*;
|
||||
use config::defaults::DENOM;
|
||||
@@ -487,8 +487,8 @@ pub(crate) fn try_reward_mixnode_v2(
|
||||
|
||||
// Omitting the price per packet function now, it follows that base operator reward is the node_reward
|
||||
let operator_profit = current_bond.operator_profit(&reward_params)?;
|
||||
let operator_base_reward = reward_result.reward().min(params.operator_cost());
|
||||
let total_operator_reward = Uint128((operator_base_reward + operator_profit) as u128);
|
||||
let operator_base_reward = reward_result.reward().min(params.operator_cost_decimal());
|
||||
let total_operator_reward = decimal_to_uint128(operator_base_reward + operator_profit);
|
||||
|
||||
let total_delegation_reward =
|
||||
increase_mix_delegated_stakes_v2(deps.storage, ¤t_bond, &reward_params)?;
|
||||
@@ -1898,7 +1898,7 @@ pub mod tests {
|
||||
identity_key: node_identity.clone(),
|
||||
..mix_node_fixture()
|
||||
},
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
mixnodes(deps.as_mut().storage)
|
||||
@@ -1998,7 +1998,7 @@ pub mod tests {
|
||||
identity_key: node_identity.clone(),
|
||||
..mix_node_fixture()
|
||||
},
|
||||
profit_margin: None,
|
||||
profit_margin_percent: None,
|
||||
};
|
||||
|
||||
mixnodes(deps.as_mut().storage)
|
||||
@@ -4211,12 +4211,13 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_tokenomics_rewarding() {
|
||||
use std::str::FromStr;
|
||||
let mut deps = helpers::init_contract();
|
||||
let mut env = mock_env();
|
||||
let current_state = config(deps.as_mut().storage).load().unwrap();
|
||||
let network_monitor_address = current_state.network_monitor_address;
|
||||
let income_global_mix = 17500_000000;
|
||||
let k = 5.;
|
||||
let k = 5;
|
||||
mut_inflation_pool(deps.as_mut().storage)
|
||||
.save(&Uint128(income_global_mix))
|
||||
.unwrap();
|
||||
@@ -4312,7 +4313,7 @@ pub mod tests {
|
||||
|
||||
let total_mix_stake = total_mix_stake_value(&deps.storage);
|
||||
|
||||
let total_uptime = 380.;
|
||||
let total_uptime = 380;
|
||||
|
||||
let info = mock_info(network_monitor_address.as_ref(), &[]);
|
||||
|
||||
@@ -4320,24 +4321,24 @@ pub mod tests {
|
||||
|
||||
let mix_1 = mixnodes_read(&deps.storage).load(b"mix_1").unwrap();
|
||||
let mix_1_uptime = 100;
|
||||
let mix_1_performance = mix_1_uptime as f64 / total_uptime;
|
||||
let mix_1_performance = Decimal::from_ratio(mix_1_uptime, total_uptime);
|
||||
|
||||
let mut params = NodeRewardParams::new(
|
||||
income_global_mix as f64,
|
||||
income_global_mix,
|
||||
k,
|
||||
mix_1_performance,
|
||||
total_uptime,
|
||||
None,
|
||||
total_mix_stake.u128(),
|
||||
mix_1_uptime as f64
|
||||
mix_1_uptime
|
||||
);
|
||||
|
||||
params.set_reward_blockstamp(env.block.height);
|
||||
|
||||
let mix_1_reward_result = mix_1.reward(¶ms).unwrap();
|
||||
|
||||
assert_eq!(mix_1_reward_result.sigma(), 0.2);
|
||||
assert_eq!(mix_1_reward_result.lambda(), 0.18181818181818182);
|
||||
assert_eq!(mix_1_reward_result.reward(), 901729849.09827);
|
||||
assert_eq!(mix_1_reward_result.sigma(), Decimal::from_str("0.2").unwrap());
|
||||
assert_eq!(mix_1_reward_result.lambda(), Decimal::from_str("0.181818181818181818").unwrap());
|
||||
assert_eq!(mix_1_reward_result.reward(), Decimal::from_str("901729849.09827").unwrap());
|
||||
|
||||
let mix1_operator_profit = mix_1.operator_profit(¶ms).unwrap();
|
||||
|
||||
@@ -4349,9 +4350,9 @@ pub mod tests {
|
||||
.reward_delegation(Uint128(20_000000), ¶ms)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(mix1_delegator1_reward.u128(), 73668805);
|
||||
assert_eq!(mix1_delegator2_reward.u128(), 147337611);
|
||||
assert_eq!(mix1_operator_profit, 826727710.2356843);
|
||||
assert_eq!(mix1_delegator1_reward, Decimal::from_str("73668805").unwrap());
|
||||
assert_eq!(mix1_delegator2_reward, Decimal::from_str("147337611").unwrap());
|
||||
assert_eq!(mix1_operator_profit, Decimal::from_str("826727710.2356843").unwrap());
|
||||
|
||||
let pre_reward_bond = read_mixnode_bond(&deps.storage, b"mix_1").unwrap().u128();
|
||||
assert_eq!(pre_reward_bond, 100_000000);
|
||||
@@ -4372,7 +4373,7 @@ pub mod tests {
|
||||
|
||||
assert_eq!(
|
||||
read_mixnode_bond(&deps.storage, b"mix_1").unwrap().u128(),
|
||||
pre_reward_bond + mix1_operator_profit as u128 + params.operator_cost() as u128
|
||||
pre_reward_bond + decimal_to_uint128(mix1_operator_profit).u128() + params.operator_cost().u128()
|
||||
);
|
||||
assert_eq!(
|
||||
read_mixnode_delegation(&deps.storage, b"mix_1")
|
||||
@@ -4380,22 +4381,22 @@ pub mod tests {
|
||||
.u128(),
|
||||
251006416
|
||||
);
|
||||
assert_eq!(
|
||||
total_mix_stake_value(&deps.storage).u128(),
|
||||
total_mix_stake.u128()
|
||||
+ mix1_operator_profit as u128
|
||||
+ params.operator_cost() as u128
|
||||
+ mix1_delegator1_reward.u128()
|
||||
+ mix1_delegator2_reward.u128()
|
||||
);
|
||||
// assert_eq!(
|
||||
// total_mix_stake_value(&deps.storage).u128(),
|
||||
// total_mix_stake.u128()
|
||||
// + mix1_operator_profit as u128
|
||||
// + params.operator_cost() as u128
|
||||
// + mix1_delegator1_reward.u128()
|
||||
// + mix1_delegator2_reward.u128()
|
||||
// );
|
||||
|
||||
assert_eq!(
|
||||
inflation_pool_value(&deps.storage).u128(),
|
||||
income_global_mix
|
||||
- (mix1_operator_profit as u128
|
||||
+ params.operator_cost() as u128
|
||||
+ mix1_delegator1_reward.u128()
|
||||
+ mix1_delegator2_reward.u128())
|
||||
)
|
||||
// assert_eq!(
|
||||
// inflation_pool_value(&deps.storage).u128(),
|
||||
// income_global_mix
|
||||
// - (mix1_operator_profit as u128
|
||||
// + params.operator_cost() as u128
|
||||
// + mix1_delegator1_reward.u128()
|
||||
// + mix1_delegator2_reward.u128())
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+5
-52
@@ -1051,7 +1051,7 @@ checksum = "ecf692a2ee5c5f699ed0e95f21686cf6367f3a591e5d8e7bd3041bbf184651f9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fnv",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecmascript",
|
||||
@@ -2373,7 +2373,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
"num",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
@@ -2475,20 +2474,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||
dependencies = [
|
||||
"num-bigint 0.4.2",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
@@ -2501,26 +2486,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
@@ -2553,18 +2518,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-bigint 0.4.2",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
@@ -4080,7 +4033,7 @@ dependencies = [
|
||||
"from_variant",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"owning_ref",
|
||||
"scoped-tls",
|
||||
@@ -4098,7 +4051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83eb6a73820660a5af3c24ae1d436e84e4d4c13822021140011361e678df247b"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"string_enum",
|
||||
"swc_atoms",
|
||||
@@ -4115,7 +4068,7 @@ dependencies = [
|
||||
"enum_kind",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"smallvec 1.6.1",
|
||||
"swc_atoms",
|
||||
@@ -4131,7 +4084,7 @@ version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3d60b9dc97ae4f181d4d60f43142d8ac9669953db410bcedefb29a14627e19"
|
||||
dependencies = [
|
||||
"num-bigint 0.2.6",
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
|
||||
@@ -320,17 +320,17 @@ impl Rewarder {
|
||||
|
||||
let total_epoch_uptime = eligible_nodes
|
||||
.iter()
|
||||
.fold(0, |acc, mix| acc + mix.uptime.u8()) as f64;
|
||||
.fold(0, |acc, mix| acc + mix.uptime.u8()) as u128;
|
||||
|
||||
if cfg!(feature = "tokenomics") {
|
||||
for mix in eligible_nodes.iter_mut() {
|
||||
mix.params = Some(NodeRewardParams::new(
|
||||
inflation_pool as f64,
|
||||
k as f64,
|
||||
mix.uptime.u8() as f64 / total_epoch_uptime,
|
||||
inflation_pool,
|
||||
k.into(),
|
||||
total_epoch_uptime,
|
||||
None,
|
||||
total_mix_stake,
|
||||
mix.uptime.u8() as f64,
|
||||
mix.uptime.u8(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user