Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b1f4560ab | |||
| 84d68efdc2 | |||
| f4f98027a0 | |||
| 4016d6b5a6 | |||
| 8cb8297681 | |||
| 7998bd20a7 | |||
| e9e53c8dff | |||
| a048cb9867 |
@@ -15,6 +15,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- native-client/socks5-client: `use_extended_packet_size` Debug config option to make the client use 'ExtendedPacketSize' for its traffic (32kB as opposed to 2kB in 1.0.2) ([#1671])
|
||||
- wasm-client: uses updated wasm-compatible `client-core` so that it's now capable of packet retransmission, cover traffic and poisson delay (among other things!) ([#1673])
|
||||
- validator-api: add `interval_operating_cost` and `profit_margin_percent` to cmpute reward estimation endpoint
|
||||
- vesting-contract: optional locked token pledge cap per account ([#1687]), defaults to 100_000 NYM
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -26,6 +27,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- socks5 client: graceful shutdown should fix error on disconnect in nym-connect ([#1591])
|
||||
- wasm-client: fixed build errors on MacOS and changed example JS code to use mainnet ([#1585])
|
||||
- gateway-client: will attempt to read now as many as 8 websocket messages at once, assuming they're already available on the socket ([#1669])
|
||||
- moved `Percent` struct to to `contracts-common`, change affects explorer-api
|
||||
|
||||
[#1541]: https://github.com/nymtech/nym/pull/1541
|
||||
[#1558]: https://github.com/nymtech/nym/pull/1558
|
||||
@@ -39,6 +41,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#1669]: https://github.com/nymtech/nym/pull/1669
|
||||
[#1671]: https://github.com/nymtech/nym/pull/1671
|
||||
[#1673]: https://github.com/nymtech/nym/pull/1673
|
||||
[#1687]: https://github.com/nymtech/nym/pull/1687
|
||||
|
||||
|
||||
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
|
||||
|
||||
Generated
+7
@@ -737,7 +737,9 @@ name = "contracts-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1584,6 +1586,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap 3.2.8",
|
||||
"dotenv",
|
||||
"contracts-common",
|
||||
"humantime-serde",
|
||||
"isocountry",
|
||||
"itertools",
|
||||
@@ -3349,6 +3352,7 @@ dependencies = [
|
||||
"coconut-interface",
|
||||
"config",
|
||||
"console-subscriber",
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"credential-storage",
|
||||
"credentials",
|
||||
@@ -6474,6 +6478,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
name = "vesting-contract"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"mixnet-contract-common",
|
||||
@@ -6487,7 +6492,9 @@ dependencies = [
|
||||
name = "vesting-contract-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"log",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
||||
@@ -15,14 +15,12 @@ use cosmrs::rpc::query::Query;
|
||||
use cosmrs::rpc::Error as TendermintRpcError;
|
||||
use cosmrs::rpc::HttpClientUrl;
|
||||
use cosmrs::tx::Msg;
|
||||
use cosmwasm_std::Uint128;
|
||||
use execute::execute;
|
||||
use network_defaults::{ChainDetails, NymNetworkDetails};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
use std::time::SystemTime;
|
||||
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
|
||||
use vesting_contract_common::QueryMsg as VestingQueryMsg;
|
||||
|
||||
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
|
||||
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
|
||||
@@ -47,6 +45,7 @@ pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
|
||||
use mixnet_contract_common::MixId;
|
||||
pub use signing_client::Client as SigningNymdClient;
|
||||
pub use traits::{VestingQueryClient, VestingSigningClient};
|
||||
use vesting_contract_common::PledgeCap;
|
||||
|
||||
pub mod coin;
|
||||
pub mod cosmwasm_client;
|
||||
@@ -482,16 +481,6 @@ impl<C> NymdClient<C> {
|
||||
self.client.get_total_supply().await
|
||||
}
|
||||
|
||||
pub async fn vesting_get_locked_pledge_cap(&self) -> Result<Uint128, NymdError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let request = VestingQueryMsg::GetLockedPledgeCap {};
|
||||
self.client
|
||||
.query_contract_smart(self.vesting_contract_address(), &request)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn simulate<I, M>(&self, messages: I) -> Result<SimulateResponse, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
@@ -737,12 +726,16 @@ impl<C> NymdClient<C> {
|
||||
#[execute("vesting")]
|
||||
fn _vesting_update_locked_pledge_cap(
|
||||
&self,
|
||||
amount: Uint128,
|
||||
address: String,
|
||||
cap: PledgeCap,
|
||||
fee: Option<Fee>,
|
||||
) -> (VestingExecuteMsg, Option<Fee>)
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
(VestingExecuteMsg::UpdateLockedPledgeCap { amount }, fee)
|
||||
(
|
||||
VestingExecuteMsg::UpdateLockedPledgeCap { address, cap },
|
||||
fee,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use async_trait::async_trait;
|
||||
use mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
||||
use mixnet_contract_common::{Gateway, MixId, MixNode};
|
||||
use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, VestingSpecification};
|
||||
use vesting_contract_common::PledgeCap;
|
||||
|
||||
#[async_trait]
|
||||
pub trait VestingSigningClient {
|
||||
@@ -105,6 +106,7 @@ pub trait VestingSigningClient {
|
||||
staking_address: Option<String>,
|
||||
vesting_spec: Option<VestingSpecification>,
|
||||
amount: Coin,
|
||||
cap: Option<PledgeCap>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
}
|
||||
@@ -382,6 +384,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
staking_address: Option<String>,
|
||||
vesting_spec: Option<VestingSpecification>,
|
||||
amount: Coin,
|
||||
cap: Option<PledgeCap>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
@@ -389,6 +392,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
owner_address: owner_address.to_string(),
|
||||
staking_address,
|
||||
vesting_spec,
|
||||
cap,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
|
||||
@@ -12,6 +12,7 @@ use validator_client::nymd::AccountId;
|
||||
use validator_client::nymd::VestingSigningClient;
|
||||
use validator_client::nymd::{CosmosCoin, Denom};
|
||||
use vesting_contract_common::messages::VestingSpecification;
|
||||
use vesting_contract_common::PledgeCap;
|
||||
|
||||
use crate::context::SigningClient;
|
||||
|
||||
@@ -34,6 +35,12 @@ pub struct Args {
|
||||
|
||||
#[clap(long)]
|
||||
pub staking_address: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Pledge cap as either absolute uNYM value or percentage, floats need to be in the 0.0 to 1.0 range and will be parsed as percentages, integers will be parsed as uNYM"
|
||||
)]
|
||||
pub pledge_cap: Option<PledgeCap>,
|
||||
}
|
||||
|
||||
pub async fn create(args: Args, client: SigningClient, network_details: &NymNetworkDetails) {
|
||||
@@ -55,6 +62,7 @@ pub async fn create(args: Args, client: SigningClient, network_details: &NymNetw
|
||||
args.staking_address,
|
||||
Some(vesting),
|
||||
coin.into(),
|
||||
args.pledge_cap,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -9,3 +9,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
cosmwasm-std = "1.0.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
thiserror = "1"
|
||||
|
||||
@@ -1,7 +1,120 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use cosmwasm_std::Decimal;
|
||||
use cosmwasm_std::Uint128;
|
||||
use schemars::JsonSchema;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::ops::Mul;
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
pub fn truncate_decimal(amount: Decimal) -> Uint128 {
|
||||
amount * Uint128::new(1)
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ContractsCommonError {
|
||||
#[error("Provided percent value ({0}) is greater than 100%")]
|
||||
InvalidPercent(Decimal),
|
||||
|
||||
#[error("{source}")]
|
||||
StdErr {
|
||||
#[from]
|
||||
source: cosmwasm_std::StdError,
|
||||
},
|
||||
}
|
||||
|
||||
/// Percent represents a value between 0 and 100%
|
||||
/// (i.e. between 0.0 and 1.0)
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
|
||||
|
||||
impl Percent {
|
||||
pub fn new(value: Decimal) -> Result<Self, ContractsCommonError> {
|
||||
if value > Decimal::one() {
|
||||
Err(ContractsCommonError::InvalidPercent(value))
|
||||
} else {
|
||||
Ok(Percent(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.0 == Decimal::zero()
|
||||
}
|
||||
|
||||
pub fn from_percentage_value(value: u64) -> Result<Self, ContractsCommonError> {
|
||||
Percent::new(Decimal::percent(value))
|
||||
}
|
||||
|
||||
pub fn value(&self) -> Decimal {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn round_to_integer(&self) -> u8 {
|
||||
let hundred = Decimal::from_ratio(100u32, 1u32);
|
||||
// we know the cast from u128 to u8 is a safe one since the internal value must be within 0 - 1 range
|
||||
truncate_decimal(hundred * self.0).u128() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Percent {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let adjusted = Decimal::from_atomics(100u32, 0).unwrap() * self.0;
|
||||
write!(f, "{}%", adjusted)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Percent {
|
||||
type Err = ContractsCommonError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Percent::new(Decimal::from_str(s)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Decimal> for Percent {
|
||||
type Output = Decimal;
|
||||
|
||||
fn mul(self, rhs: Decimal) -> Self::Output {
|
||||
self.0 * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Percent> for Decimal {
|
||||
type Output = Decimal;
|
||||
|
||||
fn mul(self, rhs: Percent) -> Self::Output {
|
||||
rhs * self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Uint128> for Percent {
|
||||
type Output = Uint128;
|
||||
|
||||
fn mul(self, rhs: Uint128) -> Self::Output {
|
||||
self.0 * rhs
|
||||
}
|
||||
}
|
||||
|
||||
// implement custom Deserialize because we want to validate Percent has the correct range
|
||||
fn de_decimal_percent<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let v = Decimal::deserialize(deserializer)?;
|
||||
if v > Decimal::one() {
|
||||
Err(D::Error::custom(
|
||||
"provided decimal percent is larger than 100%",
|
||||
))
|
||||
} else {
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: there's no reason this couldn't be used for proper binaries, but in that case
|
||||
// perhaps the struct should get renamed and moved to a "more" common crate
|
||||
|
||||
@@ -13,9 +13,6 @@ pub enum MixnetContractError {
|
||||
source: cosmwasm_std::StdError,
|
||||
},
|
||||
|
||||
#[error("Provided percent value is greater than 100%")]
|
||||
InvalidPercent,
|
||||
|
||||
#[error("Attempted to subtract decimals with overflow ({minuend}.sub({subtrahend}))")]
|
||||
OverflowDecimalSubtraction {
|
||||
minuend: Decimal,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use contracts_common::truncate_decimal;
|
||||
use cosmwasm_std::{Coin, Decimal, Uint128};
|
||||
|
||||
/// Truncates all decimal points so that the reward would fit in a `Coin` and so that we would
|
||||
@@ -17,7 +18,3 @@ pub fn truncate_reward(reward: Decimal, denom: impl Into<String>) -> Coin {
|
||||
pub fn truncate_reward_amount(reward: Decimal) -> Uint128 {
|
||||
truncate_decimal(reward)
|
||||
}
|
||||
|
||||
pub fn truncate_decimal(amount: Decimal) -> Uint128 {
|
||||
amount * Uint128::new(1)
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::rewarding::helpers::truncate_decimal;
|
||||
use crate::{Layer, RewardedSetNodeStatus};
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use cosmwasm_std::{Coin, Decimal};
|
||||
use cosmwasm_std::Addr;
|
||||
use cosmwasm_std::Coin;
|
||||
use schemars::JsonSchema;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::ops::{Index, Mul};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Index;
|
||||
|
||||
// type aliases for better reasoning about available data
|
||||
pub type IdentityKey = String;
|
||||
@@ -24,87 +21,6 @@ pub type BlockHeight = u64;
|
||||
pub type EpochEventId = u32;
|
||||
pub type IntervalEventId = u32;
|
||||
|
||||
/// Percent represents a value between 0 and 100%
|
||||
/// (i.e. between 0.0 and 1.0)
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
|
||||
|
||||
impl Percent {
|
||||
pub fn new(value: Decimal) -> Result<Self, MixnetContractError> {
|
||||
if value > Decimal::one() {
|
||||
Err(MixnetContractError::InvalidPercent)
|
||||
} else {
|
||||
Ok(Percent(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.0 == Decimal::zero()
|
||||
}
|
||||
|
||||
pub fn from_percentage_value(value: u64) -> Result<Self, MixnetContractError> {
|
||||
Percent::new(Decimal::percent(value))
|
||||
}
|
||||
|
||||
pub fn value(&self) -> Decimal {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn round_to_integer(&self) -> u8 {
|
||||
let hundred = Decimal::from_ratio(100u32, 1u32);
|
||||
// we know the cast from u128 to u8 is a safe one since the internal value must be within 0 - 1 range
|
||||
truncate_decimal(hundred * self.0).u128() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Percent {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let adjusted = Decimal::from_atomics(100u32, 0).unwrap() * self.0;
|
||||
write!(f, "{}%", adjusted)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Decimal> for Percent {
|
||||
type Output = Decimal;
|
||||
|
||||
fn mul(self, rhs: Decimal) -> Self::Output {
|
||||
self.0 * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Percent> for Decimal {
|
||||
type Output = Decimal;
|
||||
|
||||
fn mul(self, rhs: Percent) -> Self::Output {
|
||||
rhs * self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Uint128> for Percent {
|
||||
type Output = Uint128;
|
||||
|
||||
fn mul(self, rhs: Uint128) -> Self::Output {
|
||||
self.0 * rhs
|
||||
}
|
||||
}
|
||||
|
||||
// implement custom Deserialize because we want to validate Percent has the correct range
|
||||
fn de_decimal_percent<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let v = Decimal::deserialize(deserializer)?;
|
||||
if v > Decimal::one() {
|
||||
Err(D::Error::custom(
|
||||
"provided decimal percent is larger than 100%",
|
||||
))
|
||||
} else {
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct LayerDistribution {
|
||||
pub layer1: u64,
|
||||
@@ -209,7 +125,7 @@ pub struct PagedRewardedSetResponse {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use contracts_common::Percent;
|
||||
|
||||
#[test]
|
||||
fn percent_serde() {
|
||||
|
||||
@@ -6,8 +6,10 @@ edition = "2021"
|
||||
[dependencies]
|
||||
cosmwasm-std = "1.0.0"
|
||||
mixnet-contract-common = { path = "../mixnet-contract" }
|
||||
contracts-common = { path = "../contracts-common" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
log = "0.4"
|
||||
ts-rs = {version = "6.1.2", optional = true}
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::{Addr, Coin, Timestamp, Uint128};
|
||||
use log::warn;
|
||||
use mixnet_contract_common::MixId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -42,6 +46,46 @@ impl PledgeData {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub enum PledgeCap {
|
||||
Percent(Percent),
|
||||
Absolute(Uint128), // This has to be in unym
|
||||
}
|
||||
|
||||
impl FromStr for PledgeCap {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(cap: &str) -> Result<Self, Self::Err> {
|
||||
let cap = cap.replace('_', "").replace(',', ".");
|
||||
match Percent::from_str(&cap) {
|
||||
Ok(p) => {
|
||||
if p.is_zero() {
|
||||
warn!("Pledge cap set to 0%, are you sure this is right?")
|
||||
}
|
||||
Ok(PledgeCap::Percent(p))
|
||||
}
|
||||
Err(_) => {
|
||||
match cap.parse::<u128>() {
|
||||
Ok(i) => {
|
||||
if i < 100_000_000_000 {
|
||||
warn!("PledgeCap set to less then 100_000 NYM, are you sure this is right?");
|
||||
}
|
||||
Ok(PledgeCap::Absolute(Uint128::from(i)))
|
||||
}
|
||||
Err(_e) => Err(format!("Could not parse {} as Percent or Uint128", cap)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PledgeCap {
|
||||
fn default() -> Self {
|
||||
PledgeCap::Absolute(Uint128::from(100_000_000_000u128))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct OriginalVestingResponse {
|
||||
pub amount: Coin,
|
||||
@@ -98,3 +142,32 @@ pub struct AllDelegationsResponse {
|
||||
pub delegations: Vec<VestingDelegation>,
|
||||
pub start_next_after: Option<(u32, MixId, u64)>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::Uint128;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::PledgeCap;
|
||||
|
||||
#[test]
|
||||
fn test_pledge_cap_from_str() {
|
||||
assert_eq!(
|
||||
PledgeCap::from_str("0.1").unwrap(),
|
||||
PledgeCap::Percent(Percent::from_percentage_value(10).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PledgeCap::from_str("0,1").unwrap(),
|
||||
PledgeCap::Percent(Percent::from_percentage_value(10).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PledgeCap::from_str("100_000_000_000").unwrap(),
|
||||
PledgeCap::Absolute(Uint128::new(100_000_000_000))
|
||||
);
|
||||
assert_eq!(
|
||||
PledgeCap::from_str("100000000000").unwrap(),
|
||||
PledgeCap::Absolute(Uint128::new(100_000_000_000))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use cosmwasm_std::{Coin, Timestamp, Uint128};
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use mixnet_contract_common::{
|
||||
mixnode::{MixNodeConfigUpdate, MixNodeCostParams},
|
||||
Gateway, MixId, MixNode,
|
||||
@@ -6,6 +6,8 @@ use mixnet_contract_common::{
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::PledgeCap;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct InitMsg {
|
||||
@@ -83,6 +85,7 @@ pub enum ExecuteMsg {
|
||||
owner_address: String,
|
||||
staking_address: Option<String>,
|
||||
vesting_spec: Option<VestingSpecification>,
|
||||
cap: Option<PledgeCap>,
|
||||
},
|
||||
WithdrawVestedCoins {
|
||||
amount: Coin,
|
||||
@@ -120,7 +123,8 @@ pub enum ExecuteMsg {
|
||||
to_address: Option<String>,
|
||||
},
|
||||
UpdateLockedPledgeCap {
|
||||
amount: Uint128,
|
||||
address: String,
|
||||
cap: PledgeCap,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -201,7 +205,6 @@ pub enum QueryMsg {
|
||||
GetCurrentVestingPeriod {
|
||||
address: String,
|
||||
},
|
||||
GetLockedPledgeCap {},
|
||||
GetDelegationTimes {
|
||||
address: String,
|
||||
mix_id: MixId,
|
||||
|
||||
Generated
+5
@@ -221,7 +221,9 @@ name = "contracts-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1606,6 +1608,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
name = "vesting-contract"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"mixnet-contract-common",
|
||||
@@ -1619,7 +1622,9 @@ dependencies = [
|
||||
name = "vesting-contract-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"log",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
||||
@@ -15,6 +15,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
|
||||
cosmwasm-std = { version = "1.0.0 "}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::queued_migrations::migrate_to_v2_mixnet_contract;
|
||||
use crate::storage::{
|
||||
account_from_address, locked_pledge_cap, update_locked_pledge_cap, BlockTimestampSecs, ADMIN,
|
||||
DELEGATIONS, MIXNET_CONTRACT_ADDRESS, MIX_DENOM,
|
||||
account_from_address, BlockTimestampSecs, ADMIN, DELEGATIONS, MIXNET_CONTRACT_ADDRESS,
|
||||
MIX_DENOM,
|
||||
};
|
||||
use crate::traits::{
|
||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||
@@ -25,8 +25,8 @@ use vesting_contract_common::messages::{
|
||||
ExecuteMsg, InitMsg, MigrateMsg, QueryMsg, VestingSpecification,
|
||||
};
|
||||
use vesting_contract_common::{
|
||||
AllDelegationsResponse, DelegationTimesResponse, OriginalVestingResponse, Period, PledgeData,
|
||||
VestingDelegation,
|
||||
AllDelegationsResponse, DelegationTimesResponse, OriginalVestingResponse, Period, PledgeCap,
|
||||
PledgeData, VestingDelegation,
|
||||
};
|
||||
|
||||
pub const INITIAL_LOCKED_PLEDGE_CAP: Uint128 = Uint128::new(100_000_000_000);
|
||||
@@ -59,8 +59,8 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::UpdateLockedPledgeCap { amount } => {
|
||||
try_update_locked_pledge_cap(amount, info, deps)
|
||||
ExecuteMsg::UpdateLockedPledgeCap { address, cap } => {
|
||||
try_update_locked_pledge_cap(address, cap, info, deps)
|
||||
}
|
||||
ExecuteMsg::TrackReward { amount, address } => {
|
||||
try_track_reward(deps, info, amount, &address)
|
||||
@@ -88,10 +88,12 @@ pub fn execute(
|
||||
owner_address,
|
||||
staking_address,
|
||||
vesting_spec,
|
||||
cap,
|
||||
} => try_create_periodic_vesting_account(
|
||||
&owner_address,
|
||||
staking_address,
|
||||
vesting_spec,
|
||||
cap,
|
||||
info,
|
||||
env,
|
||||
deps,
|
||||
@@ -144,14 +146,18 @@ pub fn execute(
|
||||
///
|
||||
/// Callable by ADMIN only, see [instantiate].
|
||||
pub fn try_update_locked_pledge_cap(
|
||||
amount: Uint128,
|
||||
address: String,
|
||||
cap: PledgeCap,
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
if info.sender != ADMIN.load(deps.storage)? {
|
||||
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
|
||||
}
|
||||
update_locked_pledge_cap(amount, deps.storage)?;
|
||||
let mut account = account_from_address(&address, deps.storage, deps.api)?;
|
||||
|
||||
account.pledge_cap = Some(cap);
|
||||
// update_locked_pledge_cap(amount, deps.storage)?;
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
@@ -430,6 +436,7 @@ fn try_create_periodic_vesting_account(
|
||||
owner_address: &str,
|
||||
staking_address: Option<String>,
|
||||
vesting_spec: Option<VestingSpecification>,
|
||||
cap: Option<PledgeCap>,
|
||||
info: MessageInfo,
|
||||
env: Env,
|
||||
deps: DepsMut<'_>,
|
||||
@@ -437,6 +444,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();
|
||||
@@ -452,6 +460,11 @@ fn try_create_periodic_vesting_account(
|
||||
|
||||
let owner_address = deps.api.addr_validate(owner_address)?;
|
||||
let staking_address = if let Some(staking_address) = staking_address {
|
||||
let staking_account_exists =
|
||||
account_from_address(&staking_address, deps.storage, deps.api).is_ok();
|
||||
if staking_account_exists {
|
||||
return Err(ContractError::StakingAccountAlreadyExists(staking_address));
|
||||
}
|
||||
Some(deps.api.addr_validate(&staking_address)?)
|
||||
} else {
|
||||
None
|
||||
@@ -472,6 +485,7 @@ fn try_create_periodic_vesting_account(
|
||||
coin.clone(),
|
||||
start_time,
|
||||
periods,
|
||||
cap,
|
||||
deps.storage,
|
||||
)?;
|
||||
|
||||
@@ -486,7 +500,6 @@ fn try_create_periodic_vesting_account(
|
||||
#[entry_point]
|
||||
pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
|
||||
let query_res = match msg {
|
||||
QueryMsg::GetLockedPledgeCap {} => to_binary(&get_locked_pledge_cap(deps)),
|
||||
QueryMsg::LockedCoins {
|
||||
vesting_account_address,
|
||||
block_time,
|
||||
@@ -567,11 +580,6 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
/// Get locked_pledge_cap, the hard cap for staking/bonding with unvested tokens.
|
||||
pub fn get_locked_pledge_cap(deps: Deps<'_>) -> Uint128 {
|
||||
locked_pledge_cap(deps.storage)
|
||||
}
|
||||
|
||||
/// Get current vesting period for a given [crate::vesting::Account].
|
||||
pub fn try_get_current_vesting_period(
|
||||
address: &str,
|
||||
|
||||
@@ -44,6 +44,8 @@ pub enum ContractError {
|
||||
InvalidAddress(String),
|
||||
#[error("VESTING ({}): Account already exists: {0}", line!())]
|
||||
AccountAlreadyExists(String),
|
||||
#[error("VESTING ({}): Staking account already exists: {0}", line!())]
|
||||
StakingAccountAlreadyExists(String),
|
||||
#[error("VESTING ({}): Too few coins sent for vesting account creation, sent {sent}, need at least {need}", line!())]
|
||||
MinVestingFunds { sent: u128, need: u128 },
|
||||
#[error("VESTING ({}): Maximum amount of locked coins has already been pledged: {current}, cap is {cap}", line!())]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::vesting::Account;
|
||||
use crate::{contract::INITIAL_LOCKED_PLEDGE_CAP, errors::ContractError};
|
||||
use cosmwasm_std::{Addr, Api, Storage, Uint128};
|
||||
use cw_storage_plus::{Item, Map};
|
||||
use mixnet_contract_common::{IdentityKey, MixId};
|
||||
@@ -20,21 +20,6 @@ pub const DELEGATIONS: Map<'_, (u32, MixId, BlockTimestampSecs), Uint128> = Map:
|
||||
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 {
|
||||
LOCKED_PLEDGE_CAP
|
||||
.load(storage)
|
||||
.unwrap_or(INITIAL_LOCKED_PLEDGE_CAP)
|
||||
}
|
||||
|
||||
pub fn update_locked_pledge_cap(
|
||||
amount: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
LOCKED_PLEDGE_CAP.save(storage, &amount)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_delegation(
|
||||
key: (u32, MixId, BlockTimestampSecs),
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
pub mod helpers {
|
||||
use crate::contract::instantiate;
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
|
||||
use cosmwasm_std::{Addr, Coin, Empty, Env, MemoryStorage, OwnedDeps, Storage, Uint128};
|
||||
use std::str::FromStr;
|
||||
use vesting_contract_common::messages::{InitMsg, VestingSpecification};
|
||||
use vesting_contract_common::PledgeCap;
|
||||
|
||||
pub const TEST_COIN_DENOM: &str = "unym";
|
||||
|
||||
@@ -37,6 +40,7 @@ pub mod helpers {
|
||||
},
|
||||
start_time_ts,
|
||||
periods,
|
||||
None,
|
||||
storage,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -56,6 +60,29 @@ pub mod helpers {
|
||||
},
|
||||
start_time,
|
||||
periods,
|
||||
Some(PledgeCap::from_str("0.1").unwrap()),
|
||||
storage,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn vesting_account_percent_fixture(storage: &mut dyn Storage, env: &Env) -> Account {
|
||||
let start_time = env.block.time;
|
||||
let periods =
|
||||
populate_vesting_periods(start_time.seconds(), VestingSpecification::default());
|
||||
|
||||
Account::new(
|
||||
Addr::unchecked("owner"),
|
||||
Some(Addr::unchecked("staking")),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_000),
|
||||
denom: TEST_COIN_DENOM.to_string(),
|
||||
},
|
||||
start_time,
|
||||
periods,
|
||||
Some(PledgeCap::Percent(
|
||||
Percent::from_percentage_value(10).unwrap(),
|
||||
)),
|
||||
storage,
|
||||
)
|
||||
.unwrap()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::locked_pledge_cap;
|
||||
use crate::storage::save_delegation;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::DelegatingAccount;
|
||||
@@ -38,8 +37,9 @@ impl DelegatingAccount for Account {
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Response, ContractError> {
|
||||
let current_balance = self.load_balance(storage)?;
|
||||
let total_pledged_after = self.total_pledged_locked(storage, env)? + coin.amount;
|
||||
let locked_pledge_cap = locked_pledge_cap(storage);
|
||||
let total_pledged_locked = self.total_pledged_locked(storage, env)?;
|
||||
let total_pledged_after = total_pledged_locked + coin.amount;
|
||||
let locked_pledge_cap = self.absolute_pledge_cap()?;
|
||||
|
||||
if locked_pledge_cap < total_pledged_after {
|
||||
return Err(ContractError::LockedPledgeCapReached {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::PledgeData;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::locked_pledge_cap;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::GatewayBondingAccount;
|
||||
use crate::traits::VestingAccount;
|
||||
@@ -22,8 +21,9 @@ impl GatewayBondingAccount for Account {
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Response, ContractError> {
|
||||
let current_balance = self.load_balance(storage)?;
|
||||
let total_pledged_after = self.total_pledged_locked(storage, env)? + pledge.amount;
|
||||
let locked_pledge_cap = locked_pledge_cap(storage);
|
||||
let total_pledged_locked = self.total_pledged_locked(storage, env)?;
|
||||
let total_pledged_after = total_pledged_locked + pledge.amount;
|
||||
let locked_pledge_cap = self.absolute_pledge_cap()?;
|
||||
|
||||
if locked_pledge_cap < total_pledged_after {
|
||||
return Err(ContractError::LockedPledgeCapReached {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use super::Account;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::locked_pledge_cap;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::MixnodeBondingAccount;
|
||||
use crate::traits::VestingAccount;
|
||||
@@ -39,8 +38,9 @@ impl MixnodeBondingAccount for Account {
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Response, ContractError> {
|
||||
let current_balance = self.load_balance(storage)?;
|
||||
let total_pledged_after = self.total_pledged_locked(storage, env)? + pledge.amount;
|
||||
let locked_pledge_cap = locked_pledge_cap(storage);
|
||||
let total_pledged_locked = self.total_pledged_locked(storage, env)?;
|
||||
let total_pledged_after = total_pledged_locked + pledge.amount;
|
||||
let locked_pledge_cap = self.absolute_pledge_cap()?;
|
||||
|
||||
if locked_pledge_cap < total_pledged_after {
|
||||
return Err(ContractError::LockedPledgeCapReached {
|
||||
|
||||
@@ -5,12 +5,13 @@ use crate::storage::{
|
||||
remove_delegation, remove_gateway_pledge, save_account, save_balance, save_bond_pledge,
|
||||
save_gateway_pledge, save_withdrawn, BlockTimestampSecs, DELEGATIONS, KEY,
|
||||
};
|
||||
use crate::traits::VestingAccount;
|
||||
use cosmwasm_std::{Addr, Coin, Order, Storage, Timestamp, Uint128};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::MixId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vesting_contract_common::{Period, PledgeData};
|
||||
use vesting_contract_common::{Period, PledgeCap, PledgeData};
|
||||
|
||||
mod delegating_account;
|
||||
mod gateway_bonding_account;
|
||||
@@ -31,6 +32,8 @@ pub struct Account {
|
||||
pub periods: Vec<VestingPeriod>,
|
||||
pub coin: Coin,
|
||||
storage_key: u32,
|
||||
#[serde(default)]
|
||||
pub pledge_cap: Option<PledgeCap>,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
@@ -40,6 +43,7 @@ impl Account {
|
||||
coin: Coin,
|
||||
start_time: Timestamp,
|
||||
periods: Vec<VestingPeriod>,
|
||||
pledge_cap: Option<PledgeCap>,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Self, ContractError> {
|
||||
let storage_key = generate_storage_key(storage)?;
|
||||
@@ -51,12 +55,24 @@ impl Account {
|
||||
periods,
|
||||
coin,
|
||||
storage_key,
|
||||
pledge_cap,
|
||||
};
|
||||
save_account(&account, storage)?;
|
||||
account.save_balance(amount, storage)?;
|
||||
Ok(account)
|
||||
}
|
||||
|
||||
pub fn pledge_cap(&self) -> PledgeCap {
|
||||
self.pledge_cap.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn absolute_pledge_cap(&self) -> Result<Uint128, ContractError> {
|
||||
match self.pledge_cap() {
|
||||
PledgeCap::Absolute(cap) => Ok(cap),
|
||||
PledgeCap::Percent(p) => Ok(p * self.get_original_vesting().amount.amount),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coin(&self) -> Coin {
|
||||
self.coin.clone()
|
||||
}
|
||||
|
||||
@@ -123,12 +123,13 @@ impl VestingAccount for Account {
|
||||
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 withdrawn = self.load_withdrawn(storage)?;
|
||||
let max_available = self
|
||||
.get_vested_coins(Some(block_time), env, storage)?
|
||||
.amount
|
||||
.saturating_sub(withdrawn);
|
||||
|
||||
let period = self.get_current_vesting_period(block_time);
|
||||
let start_time = match period {
|
||||
Period::Before => 0,
|
||||
Period::After => u64::MAX,
|
||||
@@ -155,15 +156,8 @@ impl VestingAccount for Account {
|
||||
let block_time = block_time.unwrap_or(env.block.time);
|
||||
let delegated_free = self.get_delegated_free(Some(block_time), env, storage)?;
|
||||
|
||||
let period = self.get_current_vesting_period(block_time);
|
||||
let start_time = match period {
|
||||
Period::Before => 0,
|
||||
Period::After => u64::MAX,
|
||||
Period::In(idx) => self.periods[idx as usize].start_time,
|
||||
};
|
||||
|
||||
let delegations_before_start_time =
|
||||
self.total_delegations_at_timestamp(storage, start_time)?;
|
||||
self.total_delegations_at_timestamp(storage, block_time.seconds())?;
|
||||
|
||||
let amount = delegations_before_start_time - delegated_free.amount;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ pub fn populate_vesting_periods(
|
||||
mod tests {
|
||||
use crate::contract::*;
|
||||
use crate::storage::*;
|
||||
use crate::support::tests::helpers::vesting_account_percent_fixture;
|
||||
use crate::support::tests::helpers::{
|
||||
init_contract, vesting_account_mid_fixture, vesting_account_new_fixture, TEST_COIN_DENOM,
|
||||
};
|
||||
@@ -51,6 +52,7 @@ mod tests {
|
||||
use mixnet_contract_common::{Gateway, MixNode, Percent};
|
||||
use vesting_contract_common::messages::{ExecuteMsg, VestingSpecification};
|
||||
use vesting_contract_common::Period;
|
||||
use vesting_contract_common::PledgeCap;
|
||||
|
||||
#[test]
|
||||
fn test_account_creation() {
|
||||
@@ -61,6 +63,7 @@ mod tests {
|
||||
owner_address: "owner".to_string(),
|
||||
staking_address: Some("staking".to_string()),
|
||||
vesting_spec: None,
|
||||
cap: Some(PledgeCap::Absolute(Uint128::from(100_000_000_000u128))),
|
||||
};
|
||||
// Try creating an account when not admin
|
||||
let response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
|
||||
@@ -389,12 +392,38 @@ mod tests {
|
||||
assert_eq!(locked_coins.amount, Uint128::new(660_000_000_000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_percent_cap() {
|
||||
let mut deps = init_contract();
|
||||
let env = mock_env();
|
||||
|
||||
let account = vesting_account_percent_fixture(&mut deps.storage, &env);
|
||||
|
||||
assert_eq!(
|
||||
account.absolute_pledge_cap().unwrap(),
|
||||
Uint128::new(100_000_000_000)
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delegations() {
|
||||
let mut deps = init_contract();
|
||||
let env = mock_env();
|
||||
|
||||
let account = vesting_account_new_fixture(&mut deps.storage, &env);
|
||||
// let account = vesting_account_new_fixture(&mut deps.storage, &env);
|
||||
|
||||
let msg = ExecuteMsg::CreateAccount {
|
||||
owner_address: "owner".to_string(),
|
||||
staking_address: Some("staking".to_string()),
|
||||
vesting_spec: None,
|
||||
cap: Some(PledgeCap::Absolute(Uint128::from(100_000_000_000u128))),
|
||||
};
|
||||
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 account = load_account(&Addr::unchecked("owner"), &deps.storage)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// Try delegating too much
|
||||
let err = account.try_delegate_to_mixnode(
|
||||
@@ -434,7 +463,7 @@ mod tests {
|
||||
let balance = account.load_balance(&deps.storage).unwrap();
|
||||
assert_eq!(balance, Uint128::new(910000000000));
|
||||
|
||||
// Try delegating too much again
|
||||
// Try delegating too much againcalca
|
||||
let err = account.try_delegate_to_mixnode(
|
||||
1,
|
||||
Coin {
|
||||
@@ -449,6 +478,10 @@ mod tests {
|
||||
let total_delegations = account.total_delegations_for_mix(1, &deps.storage).unwrap();
|
||||
assert_eq!(Uint128::new(90_000_000_000), total_delegations);
|
||||
|
||||
let account = load_account(&Addr::unchecked("owner"), &deps.storage)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// Current period -> block_time: None
|
||||
let delegated_free = account
|
||||
.get_delegated_free(None, &env, &deps.storage)
|
||||
@@ -813,6 +846,7 @@ mod tests {
|
||||
},
|
||||
Timestamp::from_seconds(account_creation_timestamp),
|
||||
periods,
|
||||
Some(PledgeCap::Absolute(Uint128::from(100_000_000_000u128))),
|
||||
deps.as_mut().storage,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -27,6 +27,7 @@ maxminddb = "0.23.0"
|
||||
dotenv = "0.15.0"
|
||||
|
||||
mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
network-defaults = { path = "../common/network-defaults" }
|
||||
task = { path = "../common/task" }
|
||||
validator-client = { path = "../common/client-libs/validator-client", features=["nymd-client"] }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::client::ThreadsafeValidatorClient;
|
||||
use crate::helpers::best_effort_small_dec_to_f64;
|
||||
use crate::mix_node::models::EconomicDynamicsStats;
|
||||
use mixnet_contract_common::rewarding::helpers::truncate_decimal;
|
||||
use contracts_common::truncate_decimal;
|
||||
use mixnet_contract_common::MixId;
|
||||
|
||||
pub(crate) async fn retrieve_mixnode_econ_stats(
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
EXPLORER_API_URL=https://qa-explorer.nymtech.net/api/v1
|
||||
VALIDATOR_API_URL=https://qa-validator-api.nymtech.net
|
||||
VALIDATOR_URL=https://qa-validator.nymtech.net
|
||||
BIG_DIPPER_URL=https://qa-blocks.nymtech.net
|
||||
EXPLORER_API_URL=https://qwerty-network-explorer.qa.nymte.ch/api/v1
|
||||
VALIDATOR_API_URL=https://qwerty-validator-api.qa.nymte.ch
|
||||
VALIDATOR_URL=https://qwerty-validator.qa.nymte.ch
|
||||
BIG_DIPPER_URL=https://qwerty-blocks.nymtech.net
|
||||
CURRENCY_DENOM=unym
|
||||
CURRENCY_STAKING_DENOM=unyx
|
||||
CURRENCY_STAKING_DENOM=unyx
|
||||
@@ -7,15 +7,9 @@ const selectionChance = (economicDynamicsStats: ApiState<MixNodeEconomicDynamics
|
||||
const inclusionProbability = economicDynamicsStats?.data?.active_set_inclusion_probability;
|
||||
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
|
||||
switch (inclusionProbability) {
|
||||
case 'VeryLow':
|
||||
return 'Very Low';
|
||||
case 'VeryHigh':
|
||||
return 'Very High';
|
||||
case 'High':
|
||||
case 'Good':
|
||||
case 'Low':
|
||||
case 'Moderate':
|
||||
return inclusionProbability;
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
|
||||
@@ -19,16 +19,12 @@ const textColour = (value: EconomicsRowsType, field: string, theme: Theme) => {
|
||||
return theme.palette.warning.main;
|
||||
}
|
||||
if (field === 'selectionChance') {
|
||||
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
|
||||
switch (fieldValue) {
|
||||
case 'High':
|
||||
case 'VeryHigh':
|
||||
return theme.palette.nym.networkExplorer.selectionChance.overModerate;
|
||||
case 'Good':
|
||||
case 'Moderate':
|
||||
return theme.palette.nym.networkExplorer.selectionChance.moderate;
|
||||
case 'Low':
|
||||
case 'VeryLow':
|
||||
return theme.palette.nym.networkExplorer.selectionChance.underModerate;
|
||||
default:
|
||||
return theme.palette.nym.wallet.fee;
|
||||
|
||||
@@ -215,8 +215,7 @@ export type UptimeStoryResponse = {
|
||||
|
||||
export type MixNodeEconomicDynamicsStatsResponse = {
|
||||
stake_saturation: number;
|
||||
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
|
||||
active_set_inclusion_probability: 'High' | 'Good' | 'Low' | 'VeryLow' | 'Moderate' | 'VeryHigh';
|
||||
active_set_inclusion_probability: 'High' | 'Good' | 'Low';
|
||||
reserve_set_inclusion_probability: 'High' | 'Good' | 'Low';
|
||||
estimated_total_node_reward: number;
|
||||
estimated_operator_reward: number;
|
||||
|
||||
Generated
+1
-1
@@ -6810,4 +6810,4 @@ dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
]
|
||||
Generated
+5
@@ -665,7 +665,9 @@ name = "contracts-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5308,6 +5310,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
name = "vesting-contract"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"mixnet-contract-common",
|
||||
@@ -5321,7 +5324,9 @@ dependencies = [
|
||||
name = "vesting-contract-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"contracts-common",
|
||||
"cosmwasm-std",
|
||||
"log",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
||||
@@ -72,6 +72,7 @@ crypto = { path = "../common/crypto" }
|
||||
gateway-client = { path = "../common/client-libs/gateway-client" }
|
||||
inclusion-probability = { path = "../common/inclusion-probability" }
|
||||
mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
nymcoconut = { path = "../common/nymcoconut", optional = true }
|
||||
nymsphinx = { path = "../common/nymsphinx" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::contract_cache::{Cache, CacheNotification, ValidatorCache};
|
||||
use mixnet_contract_common::rewarding::helpers::truncate_decimal;
|
||||
use contracts_common::truncate_decimal;
|
||||
use mixnet_contract_common::{MixId, MixNodeDetails, RewardingParams};
|
||||
use rocket::fairing::AdHoc;
|
||||
use serde::Serialize;
|
||||
|
||||
Reference in New Issue
Block a user