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,
|
||||
GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond,
|
||||
MixOwnershipResponse, MixnetContractVersion, MixnodeBondResponse,
|
||||
MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
|
||||
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
|
||||
RewardedSetUpdateDetails,
|
||||
MixnodeRewardingStatusResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse,
|
||||
PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
@@ -838,6 +838,22 @@ impl<C> NymdClient<C> {
|
||||
.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.
|
||||
pub async fn get_delegation_details(
|
||||
&self,
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::reward_params::NodeRewardParams;
|
||||
use crate::ContractStateParams;
|
||||
use crate::{ContractStateParams, Layer, SphinxKey};
|
||||
use crate::{Gateway, IdentityKey, MixNode};
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -122,6 +123,10 @@ pub enum ExecuteMsg {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
GetAllDelegationValuesPaged {
|
||||
start_after: Option<(IdentityKey, Vec<u8>, u64)>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
GetBlacklistedNodes {},
|
||||
GetCurrentOperatorCost {},
|
||||
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)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {
|
||||
pub nodes_to_remove: Option<Vec<NodeToRemove>>,
|
||||
}
|
||||
|
||||
impl MigrateMsg {
|
||||
pub fn nodes_to_remove(&self) -> Vec<NodeToRemove> {
|
||||
self.nodes_to_remove.clone().unwrap_or_default()
|
||||
}
|
||||
pub v2_contract_address: String,
|
||||
pub vesting_contract_address: String,
|
||||
pub operations: Vec<V2MigrationOperation>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
|
||||
@@ -12,9 +12,7 @@ pub struct InitMsg {
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {
|
||||
pub mix_denom: String,
|
||||
}
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
||||
pub struct VestingSpecification {
|
||||
@@ -119,10 +117,11 @@ pub enum ExecuteMsg {
|
||||
UpdateLockedPledgeCap {
|
||||
amount: Uint128,
|
||||
},
|
||||
MigrateHeightsToTimestamps {
|
||||
account_id: u32,
|
||||
mix_identity: String,
|
||||
height_timestamp_map: Vec<(u64, u64)>,
|
||||
|
||||
AuthorisedUpdateToV2 {
|
||||
owner: String,
|
||||
node_identity: IdentityKey,
|
||||
mix_id: u32,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+218
-218
@@ -7,6 +7,7 @@ use crate::delegations::queries::query_mixnode_delegation;
|
||||
use crate::delegations::queries::{
|
||||
query_mixnode_delegations_paged, query_pending_delegation_events,
|
||||
};
|
||||
use crate::delegations::storage::delegations;
|
||||
use crate::error::ContractError;
|
||||
use crate::gateways::queries::query_owns_gateway;
|
||||
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::mixnodes::bonding_queries as mixnode_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::transactions::_try_remove_mixnode;
|
||||
use crate::queued_migrations::v2_migration;
|
||||
use crate::rewards::queries::{
|
||||
query_circulating_supply, query_reward_pool, query_rewarding_status, query_staking_supply,
|
||||
};
|
||||
use crate::rewards::storage as rewards_storage;
|
||||
use cosmwasm_std::{
|
||||
entry_point, to_binary, Addr, Api, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
|
||||
Storage, Uint128,
|
||||
Storage, SubMsg, Uint128,
|
||||
};
|
||||
use mixnet_contract_common::{
|
||||
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, NodeToRemove, QueryMsg,
|
||||
@@ -113,6 +116,7 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
// we must be able to perform universal compound alongside reconcile
|
||||
ExecuteMsg::CompoundReward {
|
||||
operator,
|
||||
delegator,
|
||||
@@ -126,215 +130,217 @@ pub fn execute(
|
||||
mix_identity,
|
||||
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 {} => {
|
||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
|
||||
}
|
||||
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,
|
||||
),
|
||||
_ => Err(ContractError::MaintenanceMode),
|
||||
// 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::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,
|
||||
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?)
|
||||
@@ -508,16 +517,7 @@ fn remove_malicious_node(
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
let mut response = Response::new();
|
||||
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)
|
||||
v2_migration(deps, env, msg)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -8,10 +8,7 @@ use cosmwasm_std::StdResult;
|
||||
use cosmwasm_std::{Api, Deps, Storage};
|
||||
use cw_storage_plus::{Bound, PrimaryKey};
|
||||
use mixnet_contract_common::mixnode::DelegationEvent;
|
||||
use mixnet_contract_common::{
|
||||
delegation, Delegation, IdentityKey, PagedDelegatorDelegationsResponse,
|
||||
PagedMixDelegationsResponse,
|
||||
};
|
||||
use mixnet_contract_common::{delegation, Delegation, IdentityKey, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedMixDelegationsResponse};
|
||||
|
||||
pub(crate) fn query_pending_delegation_events(
|
||||
deps: Deps<'_>,
|
||||
@@ -80,6 +77,31 @@ pub fn query_all_delegation_keys(storage: &dyn Storage) -> Result<Vec<String>, C
|
||||
|
||||
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
|
||||
pub fn debug_query_all_delegation_values(
|
||||
storage: &dyn Storage,
|
||||
|
||||
@@ -185,4 +185,7 @@ pub enum ContractError {
|
||||
|
||||
#[error("Mixnode {identity} has been blacklisted on the network")]
|
||||
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>
|
||||
// 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::storage::{
|
||||
account_from_address, locked_pledge_cap, remove_delegation, save_delegation,
|
||||
update_locked_pledge_cap, BlockTimestampSecs, ADMIN, DELEGATIONS, MIXNET_CONTRACT_ADDRESS,
|
||||
MIX_DENOM,
|
||||
update_locked_pledge_cap, BlockTimestampSecs, NodeId, ADMIN, DELEGATIONS,
|
||||
MIXNET_CONTRACT_ADDRESS, MIX_DENOM, OLD_DELEGATIONS,
|
||||
};
|
||||
use crate::traits::{
|
||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||
};
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
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,
|
||||
};
|
||||
use cw_storage_plus::Bound;
|
||||
@@ -49,96 +49,122 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
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]
|
||||
pub fn execute(
|
||||
deps: DepsMut<'_>,
|
||||
env: Env,
|
||||
_env: Env,
|
||||
info: MessageInfo,
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::UpdateLockedPledgeCap { amount } => {
|
||||
try_update_locked_pledge_cap(amount, info, deps)
|
||||
}
|
||||
ExecuteMsg::TrackReward { amount, address } => {
|
||||
try_track_reward(deps, info, amount, &address)
|
||||
}
|
||||
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::AuthorisedUpdateToV2 {
|
||||
owner,
|
||||
node_identity,
|
||||
mix_id,
|
||||
} => update_delegation_to_v2(deps, info, owner, node_identity, mix_id),
|
||||
ExecuteMsg::TrackUndelegation {
|
||||
owner,
|
||||
mix_identity,
|
||||
amount,
|
||||
} => try_track_undelegation(&owner, mix_identity, amount, 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)
|
||||
}
|
||||
ExecuteMsg::MigrateHeightsToTimestamps {
|
||||
account_id,
|
||||
mix_identity,
|
||||
height_timestamp_map,
|
||||
} => try_migrate_heights_to_timestamps(
|
||||
account_id,
|
||||
mix_identity,
|
||||
height_timestamp_map,
|
||||
info,
|
||||
deps,
|
||||
),
|
||||
_ => Err(ContractError::MaintenanceMode),
|
||||
// ExecuteMsg::UpdateLockedPledgeCap { amount } => {
|
||||
// try_update_locked_pledge_cap(amount, info, deps)
|
||||
// }
|
||||
// ExecuteMsg::TrackReward { amount, address } => {
|
||||
// try_track_reward(deps, info, amount, &address)
|
||||
// }
|
||||
// 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::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
|
||||
pub fn try_bond_gateway(
|
||||
gateway: Gateway,
|
||||
@@ -684,20 +686,21 @@ pub fn try_get_delegation_times(
|
||||
vesting_account_address: &str,
|
||||
mix_identity: String,
|
||||
) -> Result<DelegationTimesResponse, ContractError> {
|
||||
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()))
|
||||
.keys(deps.storage, None, None, Order::Ascending)
|
||||
.collect::<StdResult<Vec<_>>>()?;
|
||||
|
||||
Ok(DelegationTimesResponse {
|
||||
owner,
|
||||
account_id: account.storage_key(),
|
||||
mix_identity,
|
||||
delegation_timestamps,
|
||||
})
|
||||
Err(ContractError::MaintenanceMode)
|
||||
// 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()))
|
||||
// .keys(deps.storage, None, None, Order::Ascending)
|
||||
// .collect::<StdResult<Vec<_>>>()?;
|
||||
//
|
||||
// Ok(DelegationTimesResponse {
|
||||
// owner,
|
||||
// account_id: account.storage_key(),
|
||||
// mix_identity,
|
||||
// delegation_timestamps,
|
||||
// })
|
||||
}
|
||||
|
||||
pub fn try_get_all_delegations(
|
||||
@@ -705,35 +708,36 @@ pub fn try_get_all_delegations(
|
||||
start_after: Option<(u32, IdentityKey, BlockTimestampSecs)>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<AllDelegationsResponse, ContractError> {
|
||||
let limit = limit.unwrap_or(100).min(200) as usize;
|
||||
|
||||
let start = start_after.map(Bound::exclusive);
|
||||
let delegations = DELEGATIONS
|
||||
.range(deps.storage, start, None, Order::Ascending)
|
||||
.map(|kv| {
|
||||
kv.map(
|
||||
|((account_id, mix_identity, block_timestamp), amount)| VestingDelegation {
|
||||
account_id,
|
||||
mix_identity,
|
||||
block_timestamp,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<StdResult<Vec<_>>>()?;
|
||||
|
||||
let start_next_after = if delegations.len() < limit {
|
||||
None
|
||||
} else {
|
||||
delegations
|
||||
.last()
|
||||
.map(|delegation| delegation.storage_key())
|
||||
};
|
||||
|
||||
Ok(AllDelegationsResponse {
|
||||
delegations,
|
||||
start_next_after,
|
||||
})
|
||||
Err(ContractError::MaintenanceMode)
|
||||
// let limit = limit.unwrap_or(100).min(200) as usize;
|
||||
//
|
||||
// let start = start_after.map(Bound::exclusive);
|
||||
// let delegations = DELEGATIONS
|
||||
// .range(deps.storage, start, None, Order::Ascending)
|
||||
// .map(|kv| {
|
||||
// kv.map(
|
||||
// |((account_id, mix_identity, block_timestamp), amount)| VestingDelegation {
|
||||
// account_id,
|
||||
// mix_identity,
|
||||
// block_timestamp,
|
||||
// amount,
|
||||
// },
|
||||
// )
|
||||
// })
|
||||
// .collect::<StdResult<Vec<_>>>()?;
|
||||
//
|
||||
// let start_next_after = if delegations.len() < limit {
|
||||
// None
|
||||
// } else {
|
||||
// delegations
|
||||
// .last()
|
||||
// .map(|delegation| delegation.storage_key())
|
||||
// };
|
||||
//
|
||||
// Ok(AllDelegationsResponse {
|
||||
// delegations,
|
||||
// start_next_after,
|
||||
// })
|
||||
}
|
||||
|
||||
fn validate_funds(funds: &[Coin], mix_denom: String) -> Result<Coin, ContractError> {
|
||||
|
||||
@@ -48,4 +48,7 @@ pub enum ContractError {
|
||||
MinVestingFunds { sent: u128, need: u128 },
|
||||
#[error("VESTING ({}): Maximum amount of locked coins has already been pledged: {current}, cap is {cap}", line!())]
|
||||
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;
|
||||
|
||||
pub(crate) type BlockTimestampSecs = u64;
|
||||
pub(crate) type NodeId = u32;
|
||||
|
||||
pub const KEY: Item<'_, u32> = Item::new("key");
|
||||
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 BOND_PLEDGES: Map<'_, u32, PledgeData> = Map::new("bnd");
|
||||
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 MIXNET_CONTRACT_ADDRESS: Item<'_, String> = Item::new("mix");
|
||||
pub const MIX_DENOM: Item<'_, String> = Item::new("den");
|
||||
@@ -30,8 +33,9 @@ pub fn update_locked_pledge_cap(
|
||||
amount: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
LOCKED_PLEDGE_CAP.save(storage, &amount)?;
|
||||
Ok(())
|
||||
Err(ContractError::MaintenanceMode)
|
||||
// LOCKED_PLEDGE_CAP.save(storage, &amount)?;
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
pub fn save_delegation(
|
||||
@@ -39,15 +43,16 @@ pub fn save_delegation(
|
||||
amount: Uint128,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
DELEGATIONS.save(storage, key, &amount)?;
|
||||
Ok(())
|
||||
Err(ContractError::MaintenanceMode)
|
||||
// DELEGATIONS.save(storage, key, &amount)?;
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_delegation(
|
||||
key: (u32, IdentityKey, BlockTimestampSecs),
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError> {
|
||||
DELEGATIONS.remove(storage, key);
|
||||
OLD_DELEGATIONS.remove(storage, key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::errors::ContractError;
|
||||
use crate::storage::{
|
||||
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,
|
||||
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 cw_storage_plus::Bound;
|
||||
@@ -198,11 +198,13 @@ impl Account {
|
||||
}
|
||||
|
||||
pub fn any_delegation_for_mix(&self, mix: &str, storage: &dyn Storage) -> bool {
|
||||
DELEGATIONS
|
||||
.prefix((self.storage_key(), mix.to_string()))
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.next()
|
||||
.is_some()
|
||||
false
|
||||
//
|
||||
// DELEGATIONS
|
||||
// .prefix((self.storage_key(), mix.to_string()))
|
||||
// .range(storage, None, None, Order::Ascending)
|
||||
// .next()
|
||||
// .is_some()
|
||||
}
|
||||
|
||||
pub fn remove_delegations_for_mix(
|
||||
@@ -217,7 +219,7 @@ impl Account {
|
||||
// TODO: Test this
|
||||
loop {
|
||||
block_heights.extend(
|
||||
DELEGATIONS
|
||||
OLD_DELEGATIONS
|
||||
.prefix((self.storage_key(), mix.to_string()))
|
||||
.keys(storage, start_after, None, Order::Ascending)
|
||||
.take(limit)
|
||||
@@ -247,19 +249,23 @@ impl Account {
|
||||
mix: IdentityKey,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
Ok(DELEGATIONS
|
||||
.prefix((self.storage_key(), mix))
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||
Err(ContractError::MaintenanceMode)
|
||||
|
||||
// Ok(DELEGATIONS
|
||||
// .prefix((self.storage_key(), mix))
|
||||
// .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> {
|
||||
Ok(DELEGATIONS
|
||||
.sub_prefix(self.storage_key())
|
||||
.range(storage, None, None, Order::Ascending)
|
||||
.filter_map(|x| x.ok())
|
||||
.fold(Uint128::zero(), |acc, (_key, val)| acc + val))
|
||||
Err(ContractError::MaintenanceMode)
|
||||
|
||||
// Ok(DELEGATIONS
|
||||
// .sub_prefix(self.storage_key())
|
||||
// .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(
|
||||
|
||||
Reference in New Issue
Block a user