Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7892066f88 | |||
| 22518e277e | |||
| 53dc0a52a1 | |||
| 948c3e6423 | |||
| e006f2f4a4 | |||
| 1ba8729813 | |||
| 80c626da83 | |||
| 4cfea04475 | |||
| 3d9ee1e0c1 | |||
| 499ddbd362 | |||
| 58b23e6ee4 |
@@ -22,9 +22,9 @@ use mixnet_contract_common::{
|
|||||||
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
|
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
|
||||||
GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond,
|
GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond,
|
||||||
MixOwnershipResponse, MixnetContractVersion, MixnodeBondResponse,
|
MixOwnershipResponse, MixnetContractVersion, MixnodeBondResponse,
|
||||||
MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
|
MixnodeRewardingStatusResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
|
||||||
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
|
PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse,
|
||||||
RewardedSetUpdateDetails,
|
PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -838,6 +838,22 @@ impl<C> NymdClient<C> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_all_delegations_paged(
|
||||||
|
&self,
|
||||||
|
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
|
||||||
|
) -> Result<PagedAllDelegationsResponse, NymdError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
let request = QueryMsg::GetAllDelegationValuesPaged {
|
||||||
|
start_after,
|
||||||
|
limit: None,
|
||||||
|
};
|
||||||
|
self.client
|
||||||
|
.query_contract_smart(self.mixnet_contract_address(), &request)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks value of delegation of given client towards particular mixnode.
|
/// Checks value of delegation of given client towards particular mixnode.
|
||||||
pub async fn get_delegation_details(
|
pub async fn get_delegation_details(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::reward_params::NodeRewardParams;
|
use crate::reward_params::NodeRewardParams;
|
||||||
use crate::ContractStateParams;
|
use crate::{ContractStateParams, Layer, SphinxKey};
|
||||||
use crate::{Gateway, IdentityKey, MixNode};
|
use crate::{Gateway, IdentityKey, MixNode};
|
||||||
|
use cosmwasm_std::{Addr, Coin};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -122,6 +123,10 @@ pub enum ExecuteMsg {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
|
GetAllDelegationValuesPaged {
|
||||||
|
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
|
||||||
|
limit: Option<u32>,
|
||||||
|
},
|
||||||
GetBlacklistedNodes {},
|
GetBlacklistedNodes {},
|
||||||
GetCurrentOperatorCost {},
|
GetCurrentOperatorCost {},
|
||||||
GetRewardingValidatorAddress {},
|
GetRewardingValidatorAddress {},
|
||||||
@@ -213,16 +218,147 @@ pub enum QueryMsg {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all of those `serde rename` are here to reduce the rpc response size to bare minimum
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[serde(rename = "op")]
|
||||||
|
pub enum V2MigrationOperation {
|
||||||
|
#[serde(rename = "m1")]
|
||||||
|
MigrateOperator {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
node_identity: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "m2")]
|
||||||
|
MigrateDelegator {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
address: Addr,
|
||||||
|
|
||||||
|
#[serde(rename = "a2")]
|
||||||
|
node_identity: String,
|
||||||
|
|
||||||
|
#[serde(rename = "a3")]
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
|
||||||
|
#[serde(rename = "a4")]
|
||||||
|
new_mix_id: Option<u32>,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "m3")]
|
||||||
|
RemoveOperator {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
node_identity: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "m4")]
|
||||||
|
RemoveDelegator {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
address: Addr,
|
||||||
|
|
||||||
|
#[serde(rename = "a2")]
|
||||||
|
node_identity: String,
|
||||||
|
|
||||||
|
#[serde(rename = "a3")]
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "m5")]
|
||||||
|
MigrateGateway {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
node_identity: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "m6")]
|
||||||
|
RemoveGateway {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
node_identity: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum SpecialV2ExecuteMsg {
|
||||||
|
#[serde(rename = "m1")]
|
||||||
|
SaveOperator {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
host: String,
|
||||||
|
|
||||||
|
#[serde(rename = "a2")]
|
||||||
|
mix_port: u16,
|
||||||
|
|
||||||
|
#[serde(rename = "a3")]
|
||||||
|
verloc_port: u16,
|
||||||
|
|
||||||
|
#[serde(rename = "a4")]
|
||||||
|
http_api_port: u16,
|
||||||
|
|
||||||
|
#[serde(rename = "a5")]
|
||||||
|
sphinx_key: SphinxKey,
|
||||||
|
|
||||||
|
#[serde(rename = "a6")]
|
||||||
|
identity_key: IdentityKey,
|
||||||
|
|
||||||
|
#[serde(rename = "a7")]
|
||||||
|
version: String,
|
||||||
|
|
||||||
|
#[serde(rename = "a8")]
|
||||||
|
pledge_amount: Coin,
|
||||||
|
|
||||||
|
#[serde(rename = "a9")]
|
||||||
|
owner: Addr,
|
||||||
|
|
||||||
|
#[serde(rename = "a10")]
|
||||||
|
block_height: u64,
|
||||||
|
|
||||||
|
#[serde(rename = "a11")]
|
||||||
|
profit_margin_percent: u8,
|
||||||
|
|
||||||
|
#[serde(rename = "a12")]
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "m2")]
|
||||||
|
SaveDelegation {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
owner: Addr,
|
||||||
|
|
||||||
|
#[serde(rename = "a2")]
|
||||||
|
mix_id: u32,
|
||||||
|
|
||||||
|
#[serde(rename = "a3")]
|
||||||
|
amount: Coin,
|
||||||
|
|
||||||
|
#[serde(rename = "a4")]
|
||||||
|
block_height: u64,
|
||||||
|
|
||||||
|
#[serde(rename = "a5")]
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "m3")]
|
||||||
|
SaveGateway {
|
||||||
|
#[serde(rename = "a1")]
|
||||||
|
pledge_amount: Coin,
|
||||||
|
|
||||||
|
#[serde(rename = "a2")]
|
||||||
|
owner: Addr,
|
||||||
|
|
||||||
|
#[serde(rename = "a3")]
|
||||||
|
block_height: u64,
|
||||||
|
|
||||||
|
#[serde(rename = "a4")]
|
||||||
|
gateway: Gateway,
|
||||||
|
|
||||||
|
#[serde(rename = "a5")]
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MigrateMsg {
|
pub struct MigrateMsg {
|
||||||
pub nodes_to_remove: Option<Vec<NodeToRemove>>,
|
pub v2_contract_address: String,
|
||||||
}
|
pub vesting_contract_address: String,
|
||||||
|
pub operations: Vec<V2MigrationOperation>,
|
||||||
impl MigrateMsg {
|
|
||||||
pub fn nodes_to_remove(&self) -> Vec<NodeToRemove> {
|
|
||||||
self.nodes_to_remove.clone().unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ pub struct InitMsg {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MigrateMsg {
|
pub struct MigrateMsg {}
|
||||||
pub mix_denom: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
||||||
pub struct VestingSpecification {
|
pub struct VestingSpecification {
|
||||||
@@ -119,10 +117,11 @@ pub enum ExecuteMsg {
|
|||||||
UpdateLockedPledgeCap {
|
UpdateLockedPledgeCap {
|
||||||
amount: Uint128,
|
amount: Uint128,
|
||||||
},
|
},
|
||||||
MigrateHeightsToTimestamps {
|
|
||||||
account_id: u32,
|
AuthorisedUpdateToV2 {
|
||||||
mix_identity: String,
|
owner: String,
|
||||||
height_timestamp_map: Vec<(u64, u64)>,
|
node_identity: IdentityKey,
|
||||||
|
mix_id: u32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+218
-218
@@ -7,6 +7,7 @@ use crate::delegations::queries::query_mixnode_delegation;
|
|||||||
use crate::delegations::queries::{
|
use crate::delegations::queries::{
|
||||||
query_mixnode_delegations_paged, query_pending_delegation_events,
|
query_mixnode_delegations_paged, query_pending_delegation_events,
|
||||||
};
|
};
|
||||||
|
use crate::delegations::storage::delegations;
|
||||||
use crate::error::ContractError;
|
use crate::error::ContractError;
|
||||||
use crate::gateways::queries::query_owns_gateway;
|
use crate::gateways::queries::query_owns_gateway;
|
||||||
use crate::gateways::queries::{query_gateway_bond, query_gateways_paged};
|
use crate::gateways::queries::{query_gateway_bond, query_gateways_paged};
|
||||||
@@ -24,17 +25,19 @@ use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
|||||||
use crate::mixnet_contract_settings::transactions::try_update_rewarding_validator_address;
|
use crate::mixnet_contract_settings::transactions::try_update_rewarding_validator_address;
|
||||||
use crate::mixnodes::bonding_queries as mixnode_queries;
|
use crate::mixnodes::bonding_queries as mixnode_queries;
|
||||||
use crate::mixnodes::bonding_queries::{
|
use crate::mixnodes::bonding_queries::{
|
||||||
query_checkpoints_for_mixnode, query_mixnode_at_height, query_mixnodes_paged,
|
query_checkpoints_for_mixnode, query_mixnode_at_height, query_mixnode_bond,
|
||||||
|
query_mixnodes_paged,
|
||||||
};
|
};
|
||||||
use crate::mixnodes::layer_queries::query_layer_distribution;
|
use crate::mixnodes::layer_queries::query_layer_distribution;
|
||||||
use crate::mixnodes::transactions::_try_remove_mixnode;
|
use crate::mixnodes::transactions::_try_remove_mixnode;
|
||||||
|
use crate::queued_migrations::v2_migration;
|
||||||
use crate::rewards::queries::{
|
use crate::rewards::queries::{
|
||||||
query_circulating_supply, query_reward_pool, query_rewarding_status, query_staking_supply,
|
query_circulating_supply, query_reward_pool, query_rewarding_status, query_staking_supply,
|
||||||
};
|
};
|
||||||
use crate::rewards::storage as rewards_storage;
|
use crate::rewards::storage as rewards_storage;
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
|
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
|
||||||
Storage, Uint128,
|
Storage, SubMsg, Uint128,
|
||||||
};
|
};
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{
|
||||||
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, NodeToRemove, QueryMsg,
|
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, NodeToRemove, QueryMsg,
|
||||||
@@ -113,6 +116,7 @@ pub fn execute(
|
|||||||
msg: ExecuteMsg,
|
msg: ExecuteMsg,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
match msg {
|
match msg {
|
||||||
|
// we must be able to perform universal compound alongside reconcile
|
||||||
ExecuteMsg::CompoundReward {
|
ExecuteMsg::CompoundReward {
|
||||||
operator,
|
operator,
|
||||||
delegator,
|
delegator,
|
||||||
@@ -126,215 +130,217 @@ pub fn execute(
|
|||||||
mix_identity,
|
mix_identity,
|
||||||
proxy,
|
proxy,
|
||||||
),
|
),
|
||||||
ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
|
|
||||||
try_update_rewarding_validator_address(deps, info, address)
|
|
||||||
}
|
|
||||||
ExecuteMsg::InitEpoch {} => try_init_epoch(info, deps.storage, env),
|
|
||||||
ExecuteMsg::BondMixnode {
|
|
||||||
mix_node,
|
|
||||||
owner_signature,
|
|
||||||
} => crate::mixnodes::transactions::try_add_mixnode(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_node,
|
|
||||||
owner_signature,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UnbondMixnode {} => {
|
|
||||||
crate::mixnodes::transactions::try_remove_mixnode(&env, deps.storage, deps.api, info)
|
|
||||||
}
|
|
||||||
ExecuteMsg::UpdateMixnodeConfig {
|
|
||||||
profit_margin_percent,
|
|
||||||
} => crate::mixnodes::transactions::try_update_mixnode_config(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
profit_margin_percent,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UpdateMixnodeConfigOnBehalf {
|
|
||||||
profit_margin_percent,
|
|
||||||
owner,
|
|
||||||
} => crate::mixnodes::transactions::try_update_mixnode_config_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
profit_margin_percent,
|
|
||||||
owner,
|
|
||||||
),
|
|
||||||
ExecuteMsg::BondGateway {
|
|
||||||
gateway,
|
|
||||||
owner_signature,
|
|
||||||
} => crate::gateways::transactions::try_add_gateway(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
gateway,
|
|
||||||
owner_signature,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UnbondGateway {} => {
|
|
||||||
crate::gateways::transactions::try_remove_gateway(deps, info)
|
|
||||||
}
|
|
||||||
ExecuteMsg::UpdateContractStateParams(params) => {
|
|
||||||
crate::mixnet_contract_settings::transactions::try_update_contract_settings(
|
|
||||||
deps, info, params,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExecuteMsg::RewardMixnode { identity, params } => {
|
|
||||||
crate::rewards::transactions::try_reward_mixnode(deps, env, info, identity, params)
|
|
||||||
}
|
|
||||||
ExecuteMsg::DelegateToMixnode { mix_identity } => {
|
|
||||||
crate::delegations::transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
|
|
||||||
}
|
|
||||||
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
|
||||||
crate::delegations::transactions::try_remove_delegation_from_mixnode(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_identity,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// ExecuteMsg::RewardNextMixDelegators {
|
|
||||||
// mix_identity,
|
|
||||||
// interval_id,
|
|
||||||
// } => crate::rewards::transactions::try_reward_next_mixnode_delegators(
|
|
||||||
// deps,
|
|
||||||
// info,
|
|
||||||
// mix_identity,
|
|
||||||
// interval_id,
|
|
||||||
// ),
|
|
||||||
ExecuteMsg::DelegateToMixnodeOnBehalf {
|
|
||||||
mix_identity,
|
|
||||||
delegate,
|
|
||||||
} => crate::delegations::transactions::try_delegate_to_mixnode_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_identity,
|
|
||||||
delegate,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UndelegateFromMixnodeOnBehalf {
|
|
||||||
mix_identity,
|
|
||||||
delegate,
|
|
||||||
} => crate::delegations::transactions::try_remove_delegation_from_mixnode_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_identity,
|
|
||||||
delegate,
|
|
||||||
),
|
|
||||||
ExecuteMsg::BondMixnodeOnBehalf {
|
|
||||||
mix_node,
|
|
||||||
owner,
|
|
||||||
owner_signature,
|
|
||||||
} => crate::mixnodes::transactions::try_add_mixnode_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_node,
|
|
||||||
owner,
|
|
||||||
owner_signature,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UnbondMixnodeOnBehalf { owner } => {
|
|
||||||
crate::mixnodes::transactions::try_remove_mixnode_on_behalf(
|
|
||||||
&env,
|
|
||||||
deps.storage,
|
|
||||||
deps.api,
|
|
||||||
info,
|
|
||||||
owner,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExecuteMsg::BondGatewayOnBehalf {
|
|
||||||
gateway,
|
|
||||||
owner,
|
|
||||||
owner_signature,
|
|
||||||
} => crate::gateways::transactions::try_add_gateway_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
gateway,
|
|
||||||
owner,
|
|
||||||
owner_signature,
|
|
||||||
),
|
|
||||||
ExecuteMsg::UnbondGatewayOnBehalf { owner } => {
|
|
||||||
crate::gateways::transactions::try_remove_gateway_on_behalf(deps, info, owner)
|
|
||||||
}
|
|
||||||
ExecuteMsg::WriteRewardedSet {
|
|
||||||
rewarded_set,
|
|
||||||
expected_active_set_size,
|
|
||||||
} => crate::interval::transactions::try_write_rewarded_set(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
rewarded_set,
|
|
||||||
expected_active_set_size,
|
|
||||||
),
|
|
||||||
ExecuteMsg::AdvanceCurrentEpoch {} => crate::interval::transactions::try_advance_epoch(
|
|
||||||
env,
|
|
||||||
deps.storage,
|
|
||||||
info.sender.to_string(),
|
|
||||||
),
|
|
||||||
ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
|
|
||||||
crate::rewards::transactions::try_compound_delegator_reward(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
mix_identity,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExecuteMsg::CompoundOperatorReward {} => {
|
|
||||||
crate::rewards::transactions::try_compound_operator_reward(deps, env, info)
|
|
||||||
}
|
|
||||||
ExecuteMsg::CompoundDelegatorRewardOnBehalf {
|
|
||||||
owner,
|
|
||||||
mix_identity,
|
|
||||||
} => crate::rewards::transactions::try_compound_delegator_reward_on_behalf(
|
|
||||||
deps,
|
|
||||||
env,
|
|
||||||
info,
|
|
||||||
owner,
|
|
||||||
mix_identity,
|
|
||||||
),
|
|
||||||
ExecuteMsg::CompoundOperatorRewardOnBehalf { owner } => {
|
|
||||||
crate::rewards::transactions::try_compound_operator_reward_on_behalf(
|
|
||||||
deps, env, info, owner,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExecuteMsg::ReconcileDelegations {} => {
|
ExecuteMsg::ReconcileDelegations {} => {
|
||||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
|
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
|
||||||
}
|
}
|
||||||
ExecuteMsg::CheckpointMixnodes {} => {
|
_ => Err(ContractError::MaintenanceMode),
|
||||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
// ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
|
||||||
deps.storage,
|
// try_update_rewarding_validator_address(deps, info, address)
|
||||||
env.block.height,
|
// }
|
||||||
info,
|
// ExecuteMsg::InitEpoch {} => try_init_epoch(info, deps.storage, env),
|
||||||
)
|
// ExecuteMsg::BondMixnode {
|
||||||
}
|
// mix_node,
|
||||||
ExecuteMsg::ClaimOperatorReward {} => {
|
// owner_signature,
|
||||||
crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
|
// } => crate::mixnodes::transactions::try_add_mixnode(
|
||||||
}
|
// deps,
|
||||||
ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
|
// env,
|
||||||
crate::rewards::transactions::try_claim_operator_reward_on_behalf(
|
// info,
|
||||||
deps, &env, &info, owner,
|
// mix_node,
|
||||||
)
|
// owner_signature,
|
||||||
}
|
// ),
|
||||||
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
// ExecuteMsg::UnbondMixnode {} => {
|
||||||
crate::rewards::transactions::try_claim_delegator_reward(
|
// crate::mixnodes::transactions::try_remove_mixnode(&env, deps.storage, deps.api, info)
|
||||||
deps,
|
// }
|
||||||
&env,
|
// ExecuteMsg::UpdateMixnodeConfig {
|
||||||
&info,
|
// profit_margin_percent,
|
||||||
&mix_identity,
|
// } => crate::mixnodes::transactions::try_update_mixnode_config(
|
||||||
)
|
// deps,
|
||||||
}
|
// env,
|
||||||
ExecuteMsg::ClaimDelegatorRewardOnBehalf {
|
// info,
|
||||||
mix_identity,
|
// profit_margin_percent,
|
||||||
owner,
|
// ),
|
||||||
} => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
|
// ExecuteMsg::UpdateMixnodeConfigOnBehalf {
|
||||||
deps,
|
// profit_margin_percent,
|
||||||
&env,
|
// owner,
|
||||||
&info,
|
// } => crate::mixnodes::transactions::try_update_mixnode_config_on_behalf(
|
||||||
owner,
|
// deps,
|
||||||
&mix_identity,
|
// env,
|
||||||
),
|
// info,
|
||||||
|
// profit_margin_percent,
|
||||||
|
// owner,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::BondGateway {
|
||||||
|
// gateway,
|
||||||
|
// owner_signature,
|
||||||
|
// } => crate::gateways::transactions::try_add_gateway(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// gateway,
|
||||||
|
// owner_signature,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::UnbondGateway {} => {
|
||||||
|
// crate::gateways::transactions::try_remove_gateway(deps, info)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::UpdateContractStateParams(params) => {
|
||||||
|
// crate::mixnet_contract_settings::transactions::try_update_contract_settings(
|
||||||
|
// deps, info, params,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::RewardMixnode { identity, params } => {
|
||||||
|
// crate::rewards::transactions::try_reward_mixnode(deps, env, info, identity, params)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::DelegateToMixnode { mix_identity } => {
|
||||||
|
// crate::delegations::transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
||||||
|
// crate::delegations::transactions::try_remove_delegation_from_mixnode(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// mix_identity,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// // ExecuteMsg::RewardNextMixDelegators {
|
||||||
|
// // mix_identity,
|
||||||
|
// // interval_id,
|
||||||
|
// // } => crate::rewards::transactions::try_reward_next_mixnode_delegators(
|
||||||
|
// // deps,
|
||||||
|
// // info,
|
||||||
|
// // mix_identity,
|
||||||
|
// // interval_id,
|
||||||
|
// // ),
|
||||||
|
// ExecuteMsg::DelegateToMixnodeOnBehalf {
|
||||||
|
// mix_identity,
|
||||||
|
// delegate,
|
||||||
|
// } => crate::delegations::transactions::try_delegate_to_mixnode_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// mix_identity,
|
||||||
|
// delegate,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::UndelegateFromMixnodeOnBehalf {
|
||||||
|
// mix_identity,
|
||||||
|
// delegate,
|
||||||
|
// } => crate::delegations::transactions::try_remove_delegation_from_mixnode_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// mix_identity,
|
||||||
|
// delegate,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::BondMixnodeOnBehalf {
|
||||||
|
// mix_node,
|
||||||
|
// owner,
|
||||||
|
// owner_signature,
|
||||||
|
// } => crate::mixnodes::transactions::try_add_mixnode_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// mix_node,
|
||||||
|
// owner,
|
||||||
|
// owner_signature,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::UnbondMixnodeOnBehalf { owner } => {
|
||||||
|
// crate::mixnodes::transactions::try_remove_mixnode_on_behalf(
|
||||||
|
// &env,
|
||||||
|
// deps.storage,
|
||||||
|
// deps.api,
|
||||||
|
// info,
|
||||||
|
// owner,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::BondGatewayOnBehalf {
|
||||||
|
// gateway,
|
||||||
|
// owner,
|
||||||
|
// owner_signature,
|
||||||
|
// } => crate::gateways::transactions::try_add_gateway_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// gateway,
|
||||||
|
// owner,
|
||||||
|
// owner_signature,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::UnbondGatewayOnBehalf { owner } => {
|
||||||
|
// crate::gateways::transactions::try_remove_gateway_on_behalf(deps, info, owner)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::WriteRewardedSet {
|
||||||
|
// rewarded_set,
|
||||||
|
// expected_active_set_size,
|
||||||
|
// } => crate::interval::transactions::try_write_rewarded_set(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// rewarded_set,
|
||||||
|
// expected_active_set_size,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::AdvanceCurrentEpoch {} => crate::interval::transactions::try_advance_epoch(
|
||||||
|
// env,
|
||||||
|
// deps.storage,
|
||||||
|
// info.sender.to_string(),
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
|
||||||
|
// crate::rewards::transactions::try_compound_delegator_reward(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// mix_identity,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::CompoundOperatorReward {} => {
|
||||||
|
// crate::rewards::transactions::try_compound_operator_reward(deps, env, info)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::CompoundDelegatorRewardOnBehalf {
|
||||||
|
// owner,
|
||||||
|
// mix_identity,
|
||||||
|
// } => crate::rewards::transactions::try_compound_delegator_reward_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// env,
|
||||||
|
// info,
|
||||||
|
// owner,
|
||||||
|
// mix_identity,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::CompoundOperatorRewardOnBehalf { owner } => {
|
||||||
|
// crate::rewards::transactions::try_compound_operator_reward_on_behalf(
|
||||||
|
// deps, env, info, owner,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ExecuteMsg::CheckpointMixnodes {} => {
|
||||||
|
// crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||||
|
// deps.storage,
|
||||||
|
// env.block.height,
|
||||||
|
// info,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::ClaimOperatorReward {} => {
|
||||||
|
// crate::rewards::transactions::try_claim_operator_reward(deps, &env, &info)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::ClaimOperatorRewardOnBehalf { owner } => {
|
||||||
|
// crate::rewards::transactions::try_claim_operator_reward_on_behalf(
|
||||||
|
// deps, &env, &info, owner,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
||||||
|
// crate::rewards::transactions::try_claim_delegator_reward(
|
||||||
|
// deps,
|
||||||
|
// &env,
|
||||||
|
// &info,
|
||||||
|
// &mix_identity,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::ClaimDelegatorRewardOnBehalf {
|
||||||
|
// mix_identity,
|
||||||
|
// owner,
|
||||||
|
// } => crate::rewards::transactions::try_claim_delegator_reward_on_behalf(
|
||||||
|
// deps,
|
||||||
|
// &env,
|
||||||
|
// &info,
|
||||||
|
// owner,
|
||||||
|
// &mix_identity,
|
||||||
|
// ),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +472,9 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
|||||||
mix_identity,
|
mix_identity,
|
||||||
height,
|
height,
|
||||||
} => to_binary(&query_mixnode_at_height(deps, mix_identity, height)?),
|
} => to_binary(&query_mixnode_at_height(deps, mix_identity, height)?),
|
||||||
|
QueryMsg::GetAllDelegationValuesPaged { start_after, limit } => to_binary(
|
||||||
|
&crate::delegations::queries::query_all_delegations_paged(deps, start_after, limit)?,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(query_res?)
|
Ok(query_res?)
|
||||||
@@ -508,16 +517,7 @@ fn remove_malicious_node(
|
|||||||
|
|
||||||
#[entry_point]
|
#[entry_point]
|
||||||
pub fn migrate(deps: DepsMut<'_>, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
|
pub fn migrate(deps: DepsMut<'_>, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||||
let mut response = Response::new();
|
v2_migration(deps, env, msg)
|
||||||
for node in msg.nodes_to_remove().iter() {
|
|
||||||
let mut sub_response = remove_malicious_node(deps.storage, deps.api, &env, node)
|
|
||||||
.unwrap_or_else(|_| panic!("Could not remove node: {:?}", node));
|
|
||||||
response.messages.append(&mut sub_response.messages);
|
|
||||||
response.attributes.append(&mut sub_response.attributes);
|
|
||||||
response.events.append(&mut sub_response.events);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ use cosmwasm_std::StdResult;
|
|||||||
use cosmwasm_std::{Api, Deps, Storage};
|
use cosmwasm_std::{Api, Deps, Storage};
|
||||||
use cw_storage_plus::{Bound, PrimaryKey};
|
use cw_storage_plus::{Bound, PrimaryKey};
|
||||||
use mixnet_contract_common::mixnode::DelegationEvent;
|
use mixnet_contract_common::mixnode::DelegationEvent;
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{delegation, Delegation, IdentityKey, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedMixDelegationsResponse};
|
||||||
delegation, Delegation, IdentityKey, PagedDelegatorDelegationsResponse,
|
|
||||||
PagedMixDelegationsResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) fn query_pending_delegation_events(
|
pub(crate) fn query_pending_delegation_events(
|
||||||
deps: Deps<'_>,
|
deps: Deps<'_>,
|
||||||
@@ -80,6 +77,31 @@ pub fn query_all_delegation_keys(storage: &dyn Storage) -> Result<Vec<String>, C
|
|||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
pub(crate) fn query_all_delegations_paged(
|
||||||
|
deps: Deps<'_>,
|
||||||
|
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
|
||||||
|
limit: Option<u32>,
|
||||||
|
) -> StdResult<PagedAllDelegationsResponse> {
|
||||||
|
let limit = limit
|
||||||
|
.unwrap_or(300)
|
||||||
|
.min(500) as usize;
|
||||||
|
|
||||||
|
let start = start_after.map(Bound::exclusive);
|
||||||
|
|
||||||
|
let delegations = storage::delegations()
|
||||||
|
.range(deps.storage, start, None, Order::Ascending)
|
||||||
|
.take(limit)
|
||||||
|
.map(|res| res.map(|item| item.1))
|
||||||
|
.collect::<StdResult<Vec<_>>>()?;
|
||||||
|
|
||||||
|
let start_next_after = delegations.last().map(|del| del.storage_key());
|
||||||
|
|
||||||
|
Ok(PagedAllDelegationsResponse::new(
|
||||||
|
delegations,
|
||||||
|
start_next_after,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// This should only be exposed directly on the contract via nymd binary, not through the nymd clients
|
// This should only be exposed directly on the contract via nymd binary, not through the nymd clients
|
||||||
pub fn debug_query_all_delegation_values(
|
pub fn debug_query_all_delegation_values(
|
||||||
storage: &dyn Storage,
|
storage: &dyn Storage,
|
||||||
|
|||||||
@@ -185,4 +185,7 @@ pub enum ContractError {
|
|||||||
|
|
||||||
#[error("Mixnode {identity} has been blacklisted on the network")]
|
#[error("Mixnode {identity} has been blacklisted on the network")]
|
||||||
MixnodeBlacklisted { identity: String },
|
MixnodeBlacklisted { identity: String },
|
||||||
|
|
||||||
|
#[error("Contract is currently set to the maintenance mode - all transactions are temporarily disabled")]
|
||||||
|
MaintenanceMode,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,304 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::delegations::queries::query_mixnode_delegation;
|
||||||
|
use crate::delegations::storage::delegations;
|
||||||
|
use crate::error::ContractError;
|
||||||
|
use crate::gateways::storage::gateways;
|
||||||
|
use crate::mixnodes::storage::mixnodes;
|
||||||
|
use cosmwasm_std::{wasm_execute, Addr, BankMsg, DepsMut, Env, Response, SubMsg};
|
||||||
|
use cw_storage_plus::Map;
|
||||||
|
use mixnet_contract_common::delegation::generate_storage_key;
|
||||||
|
use mixnet_contract_common::{IdentityKey, MigrateMsg, SpecialV2ExecuteMsg, V2MigrationOperation};
|
||||||
|
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||||
|
|
||||||
|
const MIGRATED_MIXNODES: Map<IdentityKey, u8> = Map::new("migrated-mixnodes");
|
||||||
|
const MIGRATED_GATEWAYS: Map<IdentityKey, u8> = Map::new("migrated-gateways");
|
||||||
|
type OwnerXorProxy = Vec<u8>;
|
||||||
|
const MIGRATED_DELEGATES: Map<(IdentityKey, OwnerXorProxy), u8> = Map::new("migrated-delegates");
|
||||||
|
|
||||||
|
fn migrate_operator(
|
||||||
|
deps: &mut DepsMut,
|
||||||
|
v2_mixnet_contract: &str,
|
||||||
|
node_identity: String,
|
||||||
|
response: &mut Response,
|
||||||
|
) -> Result<(), ContractError> {
|
||||||
|
if MIGRATED_MIXNODES.has(deps.storage, node_identity.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!("mixnode {} has already been migrated!", node_identity);
|
||||||
|
}
|
||||||
|
MIGRATED_MIXNODES.save(deps.storage, node_identity.clone(), &1u8)?;
|
||||||
|
|
||||||
|
let bond = mixnodes()
|
||||||
|
.load(deps.storage, &node_identity)
|
||||||
|
.expect("failed to read mixnode bond");
|
||||||
|
|
||||||
|
let pledge = bond.pledge_amount.clone();
|
||||||
|
let v2_message = SpecialV2ExecuteMsg::SaveOperator {
|
||||||
|
host: bond.mix_node.host,
|
||||||
|
mix_port: bond.mix_node.mix_port,
|
||||||
|
verloc_port: bond.mix_node.verloc_port,
|
||||||
|
http_api_port: bond.mix_node.http_api_port,
|
||||||
|
sphinx_key: bond.mix_node.sphinx_key,
|
||||||
|
identity_key: bond.mix_node.identity_key,
|
||||||
|
version: bond.mix_node.version,
|
||||||
|
pledge_amount: bond.pledge_amount,
|
||||||
|
owner: bond.owner,
|
||||||
|
block_height: bond.block_height,
|
||||||
|
profit_margin_percent: bond.mix_node.profit_margin_percent,
|
||||||
|
proxy: bond.proxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: do we need separate BankMsg here, or can we just use 'funds' here directly?
|
||||||
|
let wasm_msg = wasm_execute(v2_mixnet_contract, &v2_message, vec![pledge])
|
||||||
|
.expect("failed to serialize mixnode migration msg");
|
||||||
|
response.messages.push(SubMsg::new(wasm_msg));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_gateway(
|
||||||
|
deps: &mut DepsMut,
|
||||||
|
v2_mixnet_contract: &str,
|
||||||
|
node_identity: String,
|
||||||
|
response: &mut Response,
|
||||||
|
) -> Result<(), ContractError> {
|
||||||
|
if MIGRATED_GATEWAYS.has(deps.storage, node_identity.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!("gateway {} has already been migrated!", node_identity);
|
||||||
|
}
|
||||||
|
MIGRATED_GATEWAYS.save(deps.storage, node_identity.clone(), &1u8)?;
|
||||||
|
|
||||||
|
let bond = gateways()
|
||||||
|
.load(deps.storage, &node_identity)
|
||||||
|
.expect("failed to read gateway bond");
|
||||||
|
|
||||||
|
let pledge = bond.pledge_amount.clone();
|
||||||
|
let v2_message = SpecialV2ExecuteMsg::SaveGateway {
|
||||||
|
pledge_amount: bond.pledge_amount,
|
||||||
|
owner: bond.owner,
|
||||||
|
block_height: bond.block_height,
|
||||||
|
gateway: bond.gateway,
|
||||||
|
proxy: bond.proxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: do we need separate BankMsg here, or can we just use 'funds' here directly?
|
||||||
|
let wasm_msg = wasm_execute(v2_mixnet_contract, &v2_message, vec![pledge])
|
||||||
|
.expect("failed to serialize gateway migration msg");
|
||||||
|
response.messages.push(SubMsg::new(wasm_msg));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_proxy_vesting(proxy: Option<&Addr>, vesting_contract: &str) -> bool {
|
||||||
|
if let Some(proxy) = proxy {
|
||||||
|
// bypass for my local network where I just imported contract state to fresh contract
|
||||||
|
// return true;
|
||||||
|
if proxy.as_ref() == vesting_contract {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_delegator(
|
||||||
|
deps: &mut DepsMut,
|
||||||
|
v2_mixnet_contract: &str,
|
||||||
|
vesting_contract: &str,
|
||||||
|
address: Addr,
|
||||||
|
node_identity: String,
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
new_mix_id: Option<u32>,
|
||||||
|
response: &mut Response,
|
||||||
|
) -> Result<(), ContractError> {
|
||||||
|
let owner_proxy = generate_storage_key(&address, proxy.as_ref());
|
||||||
|
|
||||||
|
let storage_key = (node_identity.clone(), owner_proxy);
|
||||||
|
if MIGRATED_DELEGATES.has(deps.storage, storage_key.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!(
|
||||||
|
"delegator {}/{} has already been migrated!",
|
||||||
|
address, node_identity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
MIGRATED_DELEGATES.save(deps.storage, storage_key, &1u8)?;
|
||||||
|
|
||||||
|
// there should only be one (as we ensured it during previous migration steps, if not, then somebody is not following the migration instructions
|
||||||
|
// and we're in an inconsistent state)
|
||||||
|
// also this entry MUST exist as we're explicitly migrating this one
|
||||||
|
let mut delegation = query_mixnode_delegation(
|
||||||
|
deps.storage,
|
||||||
|
deps.api,
|
||||||
|
node_identity.clone(),
|
||||||
|
address.clone().into_string(),
|
||||||
|
proxy.map(Addr::into_string),
|
||||||
|
)
|
||||||
|
.expect("specified delegation doesn't exist!!");
|
||||||
|
|
||||||
|
if delegation.len() != 1 {
|
||||||
|
panic!("the universal compound hasn't been run prior to this migration!!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// take ownership of the one and only entry
|
||||||
|
let delegation = delegation.pop().unwrap();
|
||||||
|
|
||||||
|
// if mix_id is `None`, it means target mixnode doesn't exist anymore -> return the tokens
|
||||||
|
// otherwise attempt to migrate it into the new contract
|
||||||
|
if let Some(migrated_mix_id) = new_mix_id {
|
||||||
|
if is_proxy_vesting(delegation.proxy.as_ref(), vesting_contract) {
|
||||||
|
let vesting_update = VestingContractExecuteMsg::AuthorisedUpdateToV2 {
|
||||||
|
owner: address.into_string(),
|
||||||
|
node_identity,
|
||||||
|
mix_id: migrated_mix_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let wasm_msg = wasm_execute(vesting_contract, &vesting_update, vec![])
|
||||||
|
.expect("failed to serialize vesting migration msg");
|
||||||
|
response.messages.push(SubMsg::new(wasm_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let stake = delegation.amount.clone();
|
||||||
|
let v2_message = SpecialV2ExecuteMsg::SaveDelegation {
|
||||||
|
owner: delegation.owner,
|
||||||
|
mix_id: migrated_mix_id,
|
||||||
|
amount: delegation.amount,
|
||||||
|
block_height: delegation.block_height,
|
||||||
|
proxy: delegation.proxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
let wasm_msg = wasm_execute(v2_mixnet_contract, &v2_message, vec![stake])
|
||||||
|
.expect("failed to serialize mixnode migration msg");
|
||||||
|
response.messages.push(SubMsg::new(wasm_msg));
|
||||||
|
} else {
|
||||||
|
// if the specified proxy matches the vesting contract address -> treat it as "proper" undelegation
|
||||||
|
// and send tokens back there
|
||||||
|
if is_proxy_vesting(delegation.proxy.as_ref(), vesting_contract) {
|
||||||
|
let vesting_track = VestingContractExecuteMsg::TrackUndelegation {
|
||||||
|
owner: delegation.owner.to_string(),
|
||||||
|
mix_identity: delegation.node_identity.clone(),
|
||||||
|
amount: delegation.amount.clone(),
|
||||||
|
};
|
||||||
|
let wasm_msg = wasm_execute(vesting_contract, &vesting_track, vec![delegation.amount])?;
|
||||||
|
response.messages.push(SubMsg::new(wasm_msg));
|
||||||
|
} else {
|
||||||
|
let to_address = delegation.proxy.unwrap_or(delegation.owner).into_string();
|
||||||
|
let return_tokens = BankMsg::Send {
|
||||||
|
to_address,
|
||||||
|
amount: vec![delegation.amount],
|
||||||
|
};
|
||||||
|
response.messages.push(SubMsg::new(return_tokens));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_operator(
|
||||||
|
deps: &mut DepsMut,
|
||||||
|
env: &Env,
|
||||||
|
node_identity: String,
|
||||||
|
) -> Result<(), ContractError> {
|
||||||
|
if !MIGRATED_MIXNODES.has(deps.storage, node_identity.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!(
|
||||||
|
"attempted to remove mixnode {} without prior migration!",
|
||||||
|
node_identity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mixnodes().remove(deps.storage, &node_identity, env.block.height)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_gateway(deps: &mut DepsMut, node_identity: String) -> Result<(), ContractError> {
|
||||||
|
if !MIGRATED_GATEWAYS.has(deps.storage, node_identity.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!(
|
||||||
|
"attempted to remove gateway {} without prior migration!",
|
||||||
|
node_identity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gateways().remove(deps.storage, &node_identity)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_delegator(
|
||||||
|
deps: &mut DepsMut,
|
||||||
|
address: Addr,
|
||||||
|
node_identity: String,
|
||||||
|
proxy: Option<Addr>,
|
||||||
|
) -> Result<(), ContractError> {
|
||||||
|
let owner_proxy = generate_storage_key(&address, proxy.as_ref());
|
||||||
|
|
||||||
|
let storage_key = (node_identity.clone(), owner_proxy);
|
||||||
|
if !MIGRATED_DELEGATES.has(deps.storage, storage_key.clone()) {
|
||||||
|
// again, panic here because this should never occur and it's incredible dangerous to let it happen
|
||||||
|
panic!(
|
||||||
|
"attempted to remove delegator {}/{} without prior migration!",
|
||||||
|
address, node_identity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = delegations()
|
||||||
|
.prefix(storage_key.clone())
|
||||||
|
.keys(deps.storage, None, None, cosmwasm_std::Order::Ascending)
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
delegations().remove(deps.storage, (storage_key.0, storage_key.1, height))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn v2_migration(
|
||||||
|
mut deps: DepsMut<'_>,
|
||||||
|
env: Env,
|
||||||
|
msg: MigrateMsg,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
let mut response = Response::new();
|
||||||
|
|
||||||
|
// note: we're explicitly failing on failures here because we expect EVERYTHING we migrate to exist
|
||||||
|
for op in msg.operations {
|
||||||
|
match op {
|
||||||
|
V2MigrationOperation::MigrateOperator { node_identity } => {
|
||||||
|
migrate_operator(
|
||||||
|
&mut deps,
|
||||||
|
&msg.v2_contract_address,
|
||||||
|
node_identity,
|
||||||
|
&mut response,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
V2MigrationOperation::MigrateGateway { node_identity } => {
|
||||||
|
migrate_gateway(
|
||||||
|
&mut deps,
|
||||||
|
&msg.v2_contract_address,
|
||||||
|
node_identity,
|
||||||
|
&mut response,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
V2MigrationOperation::MigrateDelegator {
|
||||||
|
address,
|
||||||
|
node_identity,
|
||||||
|
proxy,
|
||||||
|
new_mix_id,
|
||||||
|
} => migrate_delegator(
|
||||||
|
&mut deps,
|
||||||
|
&msg.v2_contract_address,
|
||||||
|
&msg.vesting_contract_address,
|
||||||
|
address,
|
||||||
|
node_identity,
|
||||||
|
proxy,
|
||||||
|
new_mix_id,
|
||||||
|
&mut response,
|
||||||
|
)?,
|
||||||
|
V2MigrationOperation::RemoveOperator { node_identity } => {
|
||||||
|
remove_operator(&mut deps, &env, node_identity)?;
|
||||||
|
}
|
||||||
|
V2MigrationOperation::RemoveDelegator {
|
||||||
|
address,
|
||||||
|
node_identity,
|
||||||
|
proxy,
|
||||||
|
} => remove_delegator(&mut deps, address, node_identity, proxy)?,
|
||||||
|
V2MigrationOperation::RemoveGateway { node_identity } => {
|
||||||
|
remove_gateway(&mut deps, node_identity)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|||||||
+152
-148
@@ -1,15 +1,15 @@
|
|||||||
use crate::errors::ContractError;
|
use crate::errors::ContractError;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
account_from_address, locked_pledge_cap, remove_delegation, save_delegation,
|
account_from_address, locked_pledge_cap, remove_delegation, save_delegation,
|
||||||
update_locked_pledge_cap, BlockTimestampSecs, ADMIN, DELEGATIONS, MIXNET_CONTRACT_ADDRESS,
|
update_locked_pledge_cap, BlockTimestampSecs, NodeId, ADMIN, DELEGATIONS,
|
||||||
MIX_DENOM,
|
MIXNET_CONTRACT_ADDRESS, MIX_DENOM, OLD_DELEGATIONS,
|
||||||
};
|
};
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||||
};
|
};
|
||||||
use crate::vesting::{populate_vesting_periods, Account};
|
use crate::vesting::{populate_vesting_periods, Account};
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Order,
|
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, Event, MessageInfo, Order,
|
||||||
QueryResponse, Response, StdResult, Timestamp, Uint128,
|
QueryResponse, Response, StdResult, Timestamp, Uint128,
|
||||||
};
|
};
|
||||||
use cw_storage_plus::Bound;
|
use cw_storage_plus::Bound;
|
||||||
@@ -49,96 +49,122 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
|||||||
Ok(Response::default())
|
Ok(Response::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_delegation_to_v2(
|
||||||
|
deps: DepsMut<'_>,
|
||||||
|
info: MessageInfo,
|
||||||
|
owner: String,
|
||||||
|
node_identity: String,
|
||||||
|
mix_id: NodeId,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
if info.sender != MIXNET_CONTRACT_ADDRESS.load(deps.storage)? {
|
||||||
|
return Err(ContractError::NotMixnetContract(info.sender));
|
||||||
|
}
|
||||||
|
|
||||||
|
// this MUST succeed since we know this delegation was created via vesting contract...
|
||||||
|
let account = account_from_address(&owner, deps.storage, deps.api)?;
|
||||||
|
let storage_prefix = (account.storage_key(), node_identity.clone());
|
||||||
|
let old_data = OLD_DELEGATIONS
|
||||||
|
.prefix(storage_prefix.clone())
|
||||||
|
.range(deps.storage, None, None, Order::Ascending)
|
||||||
|
.collect::<StdResult<Vec<_>>>()?;
|
||||||
|
|
||||||
|
for (timestamp, amount) in old_data {
|
||||||
|
OLD_DELEGATIONS.remove(
|
||||||
|
deps.storage,
|
||||||
|
(storage_prefix.0, storage_prefix.1.clone(), timestamp),
|
||||||
|
);
|
||||||
|
DELEGATIONS.save(deps.storage, (storage_prefix.0, mix_id, timestamp), &amount)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Response::new())
|
||||||
|
}
|
||||||
|
|
||||||
#[entry_point]
|
#[entry_point]
|
||||||
pub fn execute(
|
pub fn execute(
|
||||||
deps: DepsMut<'_>,
|
deps: DepsMut<'_>,
|
||||||
env: Env,
|
_env: Env,
|
||||||
info: MessageInfo,
|
info: MessageInfo,
|
||||||
msg: ExecuteMsg,
|
msg: ExecuteMsg,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
match msg {
|
match msg {
|
||||||
ExecuteMsg::UpdateLockedPledgeCap { amount } => {
|
ExecuteMsg::AuthorisedUpdateToV2 {
|
||||||
try_update_locked_pledge_cap(amount, info, deps)
|
owner,
|
||||||
}
|
node_identity,
|
||||||
ExecuteMsg::TrackReward { amount, address } => {
|
mix_id,
|
||||||
try_track_reward(deps, info, amount, &address)
|
} => update_delegation_to_v2(deps, info, owner, node_identity, mix_id),
|
||||||
}
|
|
||||||
ExecuteMsg::ClaimOperatorReward {} => try_claim_operator_reward(deps, info),
|
|
||||||
ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
|
||||||
try_claim_delegator_reward(deps, info, mix_identity)
|
|
||||||
}
|
|
||||||
ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
|
|
||||||
try_compound_delegator_reward(mix_identity, info, deps)
|
|
||||||
}
|
|
||||||
ExecuteMsg::CompoundOperatorReward {} => try_compound_operator_reward(info, deps),
|
|
||||||
ExecuteMsg::UpdateMixnodeConfig {
|
|
||||||
profit_margin_percent,
|
|
||||||
} => try_update_mixnode_config(profit_margin_percent, info, deps),
|
|
||||||
ExecuteMsg::UpdateMixnetAddress { address } => {
|
|
||||||
try_update_mixnet_address(address, info, deps)
|
|
||||||
}
|
|
||||||
ExecuteMsg::DelegateToMixnode {
|
|
||||||
mix_identity,
|
|
||||||
amount,
|
|
||||||
} => try_delegate_to_mixnode(mix_identity, amount, info, env, deps),
|
|
||||||
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
|
||||||
try_undelegate_from_mixnode(mix_identity, info, deps)
|
|
||||||
}
|
|
||||||
ExecuteMsg::CreateAccount {
|
|
||||||
owner_address,
|
|
||||||
staking_address,
|
|
||||||
vesting_spec,
|
|
||||||
} => try_create_periodic_vesting_account(
|
|
||||||
&owner_address,
|
|
||||||
staking_address,
|
|
||||||
vesting_spec,
|
|
||||||
info,
|
|
||||||
env,
|
|
||||||
deps,
|
|
||||||
),
|
|
||||||
ExecuteMsg::WithdrawVestedCoins { amount } => {
|
|
||||||
try_withdraw_vested_coins(amount, env, info, deps)
|
|
||||||
}
|
|
||||||
ExecuteMsg::TrackUndelegation {
|
ExecuteMsg::TrackUndelegation {
|
||||||
owner,
|
owner,
|
||||||
mix_identity,
|
mix_identity,
|
||||||
amount,
|
amount,
|
||||||
} => try_track_undelegation(&owner, mix_identity, amount, info, deps),
|
} => try_track_undelegation(&owner, mix_identity, amount, info, deps),
|
||||||
ExecuteMsg::BondMixnode {
|
_ => Err(ContractError::MaintenanceMode),
|
||||||
mix_node,
|
// ExecuteMsg::UpdateLockedPledgeCap { amount } => {
|
||||||
owner_signature,
|
// try_update_locked_pledge_cap(amount, info, deps)
|
||||||
amount,
|
// }
|
||||||
} => try_bond_mixnode(mix_node, owner_signature, amount, info, env, deps),
|
// ExecuteMsg::TrackReward { amount, address } => {
|
||||||
ExecuteMsg::UnbondMixnode {} => try_unbond_mixnode(info, deps),
|
// try_track_reward(deps, info, amount, &address)
|
||||||
ExecuteMsg::TrackUnbondMixnode { owner, amount } => {
|
// }
|
||||||
try_track_unbond_mixnode(&owner, amount, info, deps)
|
// ExecuteMsg::ClaimOperatorReward {} => try_claim_operator_reward(deps, info),
|
||||||
}
|
// ExecuteMsg::ClaimDelegatorReward { mix_identity } => {
|
||||||
ExecuteMsg::BondGateway {
|
// try_claim_delegator_reward(deps, info, mix_identity)
|
||||||
gateway,
|
// }
|
||||||
owner_signature,
|
// ExecuteMsg::CompoundDelegatorReward { mix_identity } => {
|
||||||
amount,
|
// try_compound_delegator_reward(mix_identity, info, deps)
|
||||||
} => try_bond_gateway(gateway, owner_signature, amount, info, env, deps),
|
// }
|
||||||
ExecuteMsg::UnbondGateway {} => try_unbond_gateway(info, deps),
|
// ExecuteMsg::CompoundOperatorReward {} => try_compound_operator_reward(info, deps),
|
||||||
ExecuteMsg::TrackUnbondGateway { owner, amount } => {
|
// ExecuteMsg::UpdateMixnodeConfig {
|
||||||
try_track_unbond_gateway(&owner, amount, info, deps)
|
// profit_margin_percent,
|
||||||
}
|
// } => try_update_mixnode_config(profit_margin_percent, info, deps),
|
||||||
ExecuteMsg::TransferOwnership { to_address } => {
|
// ExecuteMsg::UpdateMixnetAddress { address } => {
|
||||||
try_transfer_ownership(to_address, info, deps)
|
// try_update_mixnet_address(address, info, deps)
|
||||||
}
|
// }
|
||||||
ExecuteMsg::UpdateStakingAddress { to_address } => {
|
// ExecuteMsg::DelegateToMixnode {
|
||||||
try_update_staking_address(to_address, info, deps)
|
// mix_identity,
|
||||||
}
|
// amount,
|
||||||
ExecuteMsg::MigrateHeightsToTimestamps {
|
// } => try_delegate_to_mixnode(mix_identity, amount, info, env, deps),
|
||||||
account_id,
|
// ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
||||||
mix_identity,
|
// try_undelegate_from_mixnode(mix_identity, info, deps)
|
||||||
height_timestamp_map,
|
// }
|
||||||
} => try_migrate_heights_to_timestamps(
|
// ExecuteMsg::CreateAccount {
|
||||||
account_id,
|
// owner_address,
|
||||||
mix_identity,
|
// staking_address,
|
||||||
height_timestamp_map,
|
// vesting_spec,
|
||||||
info,
|
// } => try_create_periodic_vesting_account(
|
||||||
deps,
|
// &owner_address,
|
||||||
),
|
// staking_address,
|
||||||
|
// vesting_spec,
|
||||||
|
// info,
|
||||||
|
// env,
|
||||||
|
// deps,
|
||||||
|
// ),
|
||||||
|
// ExecuteMsg::WithdrawVestedCoins { amount } => {
|
||||||
|
// try_withdraw_vested_coins(amount, env, info, deps)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ExecuteMsg::BondMixnode {
|
||||||
|
// mix_node,
|
||||||
|
// owner_signature,
|
||||||
|
// amount,
|
||||||
|
// } => try_bond_mixnode(mix_node, owner_signature, amount, info, env, deps),
|
||||||
|
// ExecuteMsg::UnbondMixnode {} => try_unbond_mixnode(info, deps),
|
||||||
|
// ExecuteMsg::TrackUnbondMixnode { owner, amount } => {
|
||||||
|
// try_track_unbond_mixnode(&owner, amount, info, deps)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::BondGateway {
|
||||||
|
// gateway,
|
||||||
|
// owner_signature,
|
||||||
|
// amount,
|
||||||
|
// } => try_bond_gateway(gateway, owner_signature, amount, info, env, deps),
|
||||||
|
// ExecuteMsg::UnbondGateway {} => try_unbond_gateway(info, deps),
|
||||||
|
// ExecuteMsg::TrackUnbondGateway { owner, amount } => {
|
||||||
|
// try_track_unbond_gateway(&owner, amount, info, deps)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::TransferOwnership { to_address } => {
|
||||||
|
// try_transfer_ownership(to_address, info, deps)
|
||||||
|
// }
|
||||||
|
// ExecuteMsg::UpdateStakingAddress { to_address } => {
|
||||||
|
// try_update_staking_address(to_address, info, deps)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,30 +276,6 @@ fn try_update_staking_address(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_migrate_heights_to_timestamps(
|
|
||||||
account_id: u32,
|
|
||||||
mix_identity: String,
|
|
||||||
height_timestamp_map: Vec<(u64, u64)>,
|
|
||||||
info: MessageInfo,
|
|
||||||
deps: DepsMut<'_>,
|
|
||||||
) -> Result<Response, ContractError> {
|
|
||||||
if info.sender != ADMIN.load(deps.storage)? {
|
|
||||||
return Err(ContractError::NotAdmin(info.sender.as_str().to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (height, timestamp) in height_timestamp_map {
|
|
||||||
let amount = DELEGATIONS.load(deps.storage, (account_id, mix_identity.clone(), height))?;
|
|
||||||
remove_delegation((account_id, mix_identity.clone(), height), deps.storage)?;
|
|
||||||
save_delegation(
|
|
||||||
(account_id, mix_identity.clone(), timestamp),
|
|
||||||
amount,
|
|
||||||
deps.storage,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Response::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Owner or staking
|
// Owner or staking
|
||||||
pub fn try_bond_gateway(
|
pub fn try_bond_gateway(
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
@@ -684,20 +686,21 @@ pub fn try_get_delegation_times(
|
|||||||
vesting_account_address: &str,
|
vesting_account_address: &str,
|
||||||
mix_identity: String,
|
mix_identity: String,
|
||||||
) -> Result<DelegationTimesResponse, ContractError> {
|
) -> Result<DelegationTimesResponse, ContractError> {
|
||||||
let owner = deps.api.addr_validate(vesting_account_address)?;
|
Err(ContractError::MaintenanceMode)
|
||||||
let account = account_from_address(vesting_account_address, deps.storage, deps.api)?;
|
// let owner = deps.api.addr_validate(vesting_account_address)?;
|
||||||
|
// let account = account_from_address(vesting_account_address, deps.storage, deps.api)?;
|
||||||
let delegation_timestamps = DELEGATIONS
|
//
|
||||||
.prefix((account.storage_key(), mix_identity.clone()))
|
// let delegation_timestamps = DELEGATIONS
|
||||||
.keys(deps.storage, None, None, Order::Ascending)
|
// .prefix((account.storage_key(), mix_identity.clone()))
|
||||||
.collect::<StdResult<Vec<_>>>()?;
|
// .keys(deps.storage, None, None, Order::Ascending)
|
||||||
|
// .collect::<StdResult<Vec<_>>>()?;
|
||||||
Ok(DelegationTimesResponse {
|
//
|
||||||
owner,
|
// Ok(DelegationTimesResponse {
|
||||||
account_id: account.storage_key(),
|
// owner,
|
||||||
mix_identity,
|
// account_id: account.storage_key(),
|
||||||
delegation_timestamps,
|
// mix_identity,
|
||||||
})
|
// delegation_timestamps,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_all_delegations(
|
pub fn try_get_all_delegations(
|
||||||
@@ -705,35 +708,36 @@ pub fn try_get_all_delegations(
|
|||||||
start_after: Option<(u32, IdentityKey, BlockTimestampSecs)>,
|
start_after: Option<(u32, IdentityKey, BlockTimestampSecs)>,
|
||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
) -> Result<AllDelegationsResponse, ContractError> {
|
) -> Result<AllDelegationsResponse, ContractError> {
|
||||||
let limit = limit.unwrap_or(100).min(200) as usize;
|
Err(ContractError::MaintenanceMode)
|
||||||
|
// let limit = limit.unwrap_or(100).min(200) as usize;
|
||||||
let start = start_after.map(Bound::exclusive);
|
//
|
||||||
let delegations = DELEGATIONS
|
// let start = start_after.map(Bound::exclusive);
|
||||||
.range(deps.storage, start, None, Order::Ascending)
|
// let delegations = DELEGATIONS
|
||||||
.map(|kv| {
|
// .range(deps.storage, start, None, Order::Ascending)
|
||||||
kv.map(
|
// .map(|kv| {
|
||||||
|((account_id, mix_identity, block_timestamp), amount)| VestingDelegation {
|
// kv.map(
|
||||||
account_id,
|
// |((account_id, mix_identity, block_timestamp), amount)| VestingDelegation {
|
||||||
mix_identity,
|
// account_id,
|
||||||
block_timestamp,
|
// mix_identity,
|
||||||
amount,
|
// block_timestamp,
|
||||||
},
|
// amount,
|
||||||
)
|
// },
|
||||||
})
|
// )
|
||||||
.collect::<StdResult<Vec<_>>>()?;
|
// })
|
||||||
|
// .collect::<StdResult<Vec<_>>>()?;
|
||||||
let start_next_after = if delegations.len() < limit {
|
//
|
||||||
None
|
// let start_next_after = if delegations.len() < limit {
|
||||||
} else {
|
// None
|
||||||
delegations
|
// } else {
|
||||||
.last()
|
// delegations
|
||||||
.map(|delegation| delegation.storage_key())
|
// .last()
|
||||||
};
|
// .map(|delegation| delegation.storage_key())
|
||||||
|
// };
|
||||||
Ok(AllDelegationsResponse {
|
//
|
||||||
delegations,
|
// Ok(AllDelegationsResponse {
|
||||||
start_next_after,
|
// delegations,
|
||||||
})
|
// start_next_after,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_funds(funds: &[Coin], mix_denom: String) -> Result<Coin, ContractError> {
|
fn validate_funds(funds: &[Coin], mix_denom: String) -> Result<Coin, ContractError> {
|
||||||
|
|||||||
@@ -48,4 +48,7 @@ pub enum ContractError {
|
|||||||
MinVestingFunds { sent: u128, need: u128 },
|
MinVestingFunds { sent: u128, need: u128 },
|
||||||
#[error("VESTING ({}): Maximum amount of locked coins has already been pledged: {current}, cap is {cap}", line!())]
|
#[error("VESTING ({}): Maximum amount of locked coins has already been pledged: {current}, cap is {cap}", line!())]
|
||||||
LockedPledgeCapReached { current: Uint128, cap: Uint128 },
|
LockedPledgeCapReached { current: Uint128, cap: Uint128 },
|
||||||
|
|
||||||
|
#[error("Contract is currently set to the maintenance mode - all transactions are temporarily disabled")]
|
||||||
|
MaintenanceMode,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use mixnet_contract_common::IdentityKey;
|
|||||||
use vesting_contract_common::PledgeData;
|
use vesting_contract_common::PledgeData;
|
||||||
|
|
||||||
pub(crate) type BlockTimestampSecs = u64;
|
pub(crate) type BlockTimestampSecs = u64;
|
||||||
|
pub(crate) type NodeId = u32;
|
||||||
|
|
||||||
pub const KEY: Item<'_, u32> = Item::new("key");
|
pub const KEY: Item<'_, u32> = Item::new("key");
|
||||||
const ACCOUNTS: Map<'_, String, Account> = Map::new("acc");
|
const ACCOUNTS: Map<'_, String, Account> = Map::new("acc");
|
||||||
@@ -14,7 +15,9 @@ const BALANCES: Map<'_, u32, Uint128> = Map::new("blc");
|
|||||||
const WITHDRAWNS: Map<'_, u32, Uint128> = Map::new("wthd");
|
const WITHDRAWNS: Map<'_, u32, Uint128> = Map::new("wthd");
|
||||||
const BOND_PLEDGES: Map<'_, u32, PledgeData> = Map::new("bnd");
|
const BOND_PLEDGES: Map<'_, u32, PledgeData> = Map::new("bnd");
|
||||||
const GATEWAY_PLEDGES: Map<'_, u32, PledgeData> = Map::new("gtw");
|
const GATEWAY_PLEDGES: Map<'_, u32, PledgeData> = Map::new("gtw");
|
||||||
pub const DELEGATIONS: Map<'_, (u32, IdentityKey, BlockTimestampSecs), Uint128> = Map::new("dlg");
|
pub const OLD_DELEGATIONS: Map<'_, (u32, IdentityKey, BlockTimestampSecs), Uint128> =
|
||||||
|
Map::new("dlg");
|
||||||
|
pub const DELEGATIONS: Map<'_, (u32, NodeId, BlockTimestampSecs), Uint128> = Map::new("dlg_v2");
|
||||||
pub const ADMIN: Item<'_, String> = Item::new("adm");
|
pub const ADMIN: Item<'_, String> = Item::new("adm");
|
||||||
pub const MIXNET_CONTRACT_ADDRESS: Item<'_, String> = Item::new("mix");
|
pub const MIXNET_CONTRACT_ADDRESS: Item<'_, String> = Item::new("mix");
|
||||||
pub const MIX_DENOM: Item<'_, String> = Item::new("den");
|
pub const MIX_DENOM: Item<'_, String> = Item::new("den");
|
||||||
@@ -30,8 +33,9 @@ pub fn update_locked_pledge_cap(
|
|||||||
amount: Uint128,
|
amount: Uint128,
|
||||||
storage: &mut dyn Storage,
|
storage: &mut dyn Storage,
|
||||||
) -> Result<(), ContractError> {
|
) -> Result<(), ContractError> {
|
||||||
LOCKED_PLEDGE_CAP.save(storage, &amount)?;
|
Err(ContractError::MaintenanceMode)
|
||||||
Ok(())
|
// LOCKED_PLEDGE_CAP.save(storage, &amount)?;
|
||||||
|
// Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_delegation(
|
pub fn save_delegation(
|
||||||
@@ -39,15 +43,16 @@ pub fn save_delegation(
|
|||||||
amount: Uint128,
|
amount: Uint128,
|
||||||
storage: &mut dyn Storage,
|
storage: &mut dyn Storage,
|
||||||
) -> Result<(), ContractError> {
|
) -> Result<(), ContractError> {
|
||||||
DELEGATIONS.save(storage, key, &amount)?;
|
Err(ContractError::MaintenanceMode)
|
||||||
Ok(())
|
// DELEGATIONS.save(storage, key, &amount)?;
|
||||||
|
// Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_delegation(
|
pub fn remove_delegation(
|
||||||
key: (u32, IdentityKey, BlockTimestampSecs),
|
key: (u32, IdentityKey, BlockTimestampSecs),
|
||||||
storage: &mut dyn Storage,
|
storage: &mut dyn Storage,
|
||||||
) -> Result<(), ContractError> {
|
) -> Result<(), ContractError> {
|
||||||
DELEGATIONS.remove(storage, key);
|
OLD_DELEGATIONS.remove(storage, key);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::errors::ContractError;
|
|||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
load_balance, load_bond_pledge, load_gateway_pledge, load_withdrawn, remove_bond_pledge,
|
load_balance, load_bond_pledge, load_gateway_pledge, load_withdrawn, remove_bond_pledge,
|
||||||
remove_delegation, remove_gateway_pledge, save_account, save_balance, save_bond_pledge,
|
remove_delegation, remove_gateway_pledge, save_account, save_balance, save_bond_pledge,
|
||||||
save_gateway_pledge, save_withdrawn, BlockTimestampSecs, DELEGATIONS, KEY,
|
save_gateway_pledge, save_withdrawn, BlockTimestampSecs, DELEGATIONS, KEY, OLD_DELEGATIONS,
|
||||||
};
|
};
|
||||||
use cosmwasm_std::{Addr, Coin, Order, Storage, Timestamp, Uint128};
|
use cosmwasm_std::{Addr, Coin, Order, Storage, Timestamp, Uint128};
|
||||||
use cw_storage_plus::Bound;
|
use cw_storage_plus::Bound;
|
||||||
@@ -198,11 +198,13 @@ impl Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn any_delegation_for_mix(&self, mix: &str, storage: &dyn Storage) -> bool {
|
pub fn any_delegation_for_mix(&self, mix: &str, storage: &dyn Storage) -> bool {
|
||||||
DELEGATIONS
|
false
|
||||||
.prefix((self.storage_key(), mix.to_string()))
|
//
|
||||||
.range(storage, None, None, Order::Ascending)
|
// DELEGATIONS
|
||||||
.next()
|
// .prefix((self.storage_key(), mix.to_string()))
|
||||||
.is_some()
|
// .range(storage, None, None, Order::Ascending)
|
||||||
|
// .next()
|
||||||
|
// .is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_delegations_for_mix(
|
pub fn remove_delegations_for_mix(
|
||||||
@@ -217,7 +219,7 @@ impl Account {
|
|||||||
// TODO: Test this
|
// TODO: Test this
|
||||||
loop {
|
loop {
|
||||||
block_heights.extend(
|
block_heights.extend(
|
||||||
DELEGATIONS
|
OLD_DELEGATIONS
|
||||||
.prefix((self.storage_key(), mix.to_string()))
|
.prefix((self.storage_key(), mix.to_string()))
|
||||||
.keys(storage, start_after, None, Order::Ascending)
|
.keys(storage, start_after, None, Order::Ascending)
|
||||||
.take(limit)
|
.take(limit)
|
||||||
@@ -247,19 +249,23 @@ impl Account {
|
|||||||
mix: IdentityKey,
|
mix: IdentityKey,
|
||||||
storage: &dyn Storage,
|
storage: &dyn Storage,
|
||||||
) -> Result<Uint128, ContractError> {
|
) -> Result<Uint128, ContractError> {
|
||||||
Ok(DELEGATIONS
|
Err(ContractError::MaintenanceMode)
|
||||||
.prefix((self.storage_key(), mix))
|
|
||||||
.range(storage, None, None, Order::Ascending)
|
// Ok(DELEGATIONS
|
||||||
.filter_map(|x| x.ok())
|
// .prefix((self.storage_key(), mix))
|
||||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
// .range(storage, None, None, Order::Ascending)
|
||||||
|
// .filter_map(|x| x.ok())
|
||||||
|
// .fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_delegations(&self, storage: &dyn Storage) -> Result<Uint128, ContractError> {
|
pub fn total_delegations(&self, storage: &dyn Storage) -> Result<Uint128, ContractError> {
|
||||||
Ok(DELEGATIONS
|
Err(ContractError::MaintenanceMode)
|
||||||
.sub_prefix(self.storage_key())
|
|
||||||
.range(storage, None, None, Order::Ascending)
|
// Ok(DELEGATIONS
|
||||||
.filter_map(|x| x.ok())
|
// .sub_prefix(self.storage_key())
|
||||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
// .range(storage, None, None, Order::Ascending)
|
||||||
|
// .filter_map(|x| x.ok())
|
||||||
|
// .fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_delegations_at_timestamp(
|
pub fn total_delegations_at_timestamp(
|
||||||
|
|||||||
Reference in New Issue
Block a user