1use crate::delegation::OwnerProxySubKey;
5use crate::error::MixnetContractError;
6use crate::families::FamilyHead;
7use crate::gateway::GatewayConfigUpdate;
8use crate::helpers::IntoBaseDecimal;
9use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
10use crate::reward_params::{
11 IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
12};
13use crate::{
14 delegation, ContractStateParams, EpochEventId, IntervalEventId, Layer, LayerAssignment, MixId,
15 Percent,
16};
17use crate::{Gateway, IdentityKey, MixNode};
18use contracts_common::signing::MessageSignature;
19use cosmwasm_std::{Coin, Decimal};
20use schemars::JsonSchema;
21use serde::{Deserialize, Serialize};
22use std::time::Duration;
23
24#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
25#[serde(rename_all = "snake_case")]
26pub struct InstantiateMsg {
27 pub rewarding_validator_address: String,
28 pub vesting_contract_address: String,
29
30 pub rewarding_denom: String,
31 pub epochs_in_interval: u32,
32 pub epoch_duration: Duration,
33 pub initial_rewarding_params: InitialRewardingParams,
34}
35
36#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
37#[serde(rename_all = "snake_case")]
38pub struct InitialRewardingParams {
39 pub initial_reward_pool: Decimal,
40 pub initial_staking_supply: Decimal,
41
42 pub staking_supply_scale_factor: Percent,
43 pub sybil_resistance: Percent,
44 pub active_set_work_factor: Decimal,
45 pub interval_pool_emission: Percent,
46
47 pub rewarded_set_size: u32,
48 pub active_set_size: u32,
49}
50
51impl InitialRewardingParams {
52 pub fn into_rewarding_params(
53 self,
54 epochs_in_interval: u32,
55 ) -> Result<RewardingParams, MixnetContractError> {
56 let epoch_reward_budget = self.initial_reward_pool
57 / epochs_in_interval.into_base_decimal()?
58 * self.interval_pool_emission;
59 let stake_saturation_point =
60 self.initial_staking_supply / self.rewarded_set_size.into_base_decimal()?;
61
62 Ok(RewardingParams {
63 interval: IntervalRewardParams {
64 reward_pool: self.initial_reward_pool,
65 staking_supply: self.initial_staking_supply,
66 staking_supply_scale_factor: self.staking_supply_scale_factor,
67 epoch_reward_budget,
68 stake_saturation_point,
69 sybil_resistance: self.sybil_resistance,
70 active_set_work_factor: self.active_set_work_factor,
71 interval_pool_emission: self.interval_pool_emission,
72 },
73 rewarded_set_size: self.rewarded_set_size,
74 active_set_size: self.active_set_size,
75 })
76 }
77}
78
79#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
80#[serde(rename_all = "snake_case")]
81pub enum ExecuteMsg {
82 AssignNodeLayer {
83 mix_id: MixId,
84 layer: Layer,
85 },
86 CreateFamily {
89 label: String,
90 },
91 JoinFamily {
93 join_permit: MessageSignature,
94 family_head: FamilyHead,
95 },
96 LeaveFamily {
97 family_head: FamilyHead,
98 },
99 KickFamilyMember {
100 member: IdentityKey,
101 },
102 CreateFamilyOnBehalf {
103 owner_address: String,
104 label: String,
105 },
106 JoinFamilyOnBehalf {
108 member_address: String,
109 join_permit: MessageSignature,
110 family_head: FamilyHead,
111 },
112 LeaveFamilyOnBehalf {
113 member_address: String,
114 family_head: FamilyHead,
115 },
116 KickFamilyMemberOnBehalf {
117 head_address: String,
118 member: IdentityKey,
119 },
120
121 UpdateRewardingValidatorAddress {
123 address: String,
124 },
125 UpdateContractStateParams {
126 updated_parameters: ContractStateParams,
127 },
128 UpdateActiveSetSize {
129 active_set_size: u32,
130 force_immediately: bool,
131 },
132 UpdateRewardingParams {
133 updated_params: IntervalRewardingParamsUpdate,
134 force_immediately: bool,
135 },
136 UpdateIntervalConfig {
137 epochs_in_interval: u32,
138 epoch_duration_secs: u64,
139 force_immediately: bool,
140 },
141 BeginEpochTransition {},
142 AdvanceCurrentEpoch {
143 new_rewarded_set: Vec<LayerAssignment>,
144 expected_active_set_size: u32,
146 },
147 ReconcileEpochEvents {
148 limit: Option<u32>,
149 },
150
151 BondMixnode {
153 mix_node: MixNode,
154 cost_params: MixNodeCostParams,
155 owner_signature: MessageSignature,
156 },
157 BondMixnodeOnBehalf {
158 mix_node: MixNode,
159 cost_params: MixNodeCostParams,
160 owner_signature: MessageSignature,
161 owner: String,
162 },
163 PledgeMore {},
164 PledgeMoreOnBehalf {
165 owner: String,
166 },
167 DecreasePledge {
168 decrease_by: Coin,
169 },
170 DecreasePledgeOnBehalf {
171 owner: String,
172 decrease_by: Coin,
173 },
174 UnbondMixnode {},
175 UnbondMixnodeOnBehalf {
176 owner: String,
177 },
178 UpdateMixnodeCostParams {
179 new_costs: MixNodeCostParams,
180 },
181 UpdateMixnodeCostParamsOnBehalf {
182 new_costs: MixNodeCostParams,
183 owner: String,
184 },
185 UpdateMixnodeConfig {
186 new_config: MixNodeConfigUpdate,
187 },
188 UpdateMixnodeConfigOnBehalf {
189 new_config: MixNodeConfigUpdate,
190 owner: String,
191 },
192
193 BondGateway {
195 gateway: Gateway,
196 owner_signature: MessageSignature,
197 },
198 BondGatewayOnBehalf {
199 gateway: Gateway,
200 owner: String,
201 owner_signature: MessageSignature,
202 },
203 UnbondGateway {},
204 UnbondGatewayOnBehalf {
205 owner: String,
206 },
207 UpdateGatewayConfig {
208 new_config: GatewayConfigUpdate,
209 },
210 UpdateGatewayConfigOnBehalf {
211 new_config: GatewayConfigUpdate,
212 owner: String,
213 },
214
215 DelegateToMixnode {
217 mix_id: MixId,
218 },
219 DelegateToMixnodeOnBehalf {
220 mix_id: MixId,
221 delegate: String,
222 },
223 UndelegateFromMixnode {
224 mix_id: MixId,
225 },
226 UndelegateFromMixnodeOnBehalf {
227 mix_id: MixId,
228 delegate: String,
229 },
230
231 RewardMixnode {
233 mix_id: MixId,
234 performance: Performance,
235 },
236 WithdrawOperatorReward {},
237 WithdrawOperatorRewardOnBehalf {
238 owner: String,
239 },
240 WithdrawDelegatorReward {
241 mix_id: MixId,
242 },
243 WithdrawDelegatorRewardOnBehalf {
244 mix_id: MixId,
245 owner: String,
246 },
247
248 #[cfg(feature = "contract-testing")]
250 TestingResolveAllPendingEvents {
251 limit: Option<u32>,
252 },
253}
254
255impl ExecuteMsg {
256 pub fn default_memo(&self) -> String {
257 match self {
258 ExecuteMsg::AssignNodeLayer { mix_id, layer } => {
259 format!("assigning mix {mix_id} for layer {layer:?}")
260 }
261 ExecuteMsg::CreateFamily { .. } => "crating node family with".to_string(),
262 ExecuteMsg::JoinFamily { family_head, .. } => {
263 format!("joining family {family_head}")
264 }
265 ExecuteMsg::LeaveFamily { family_head, .. } => {
266 format!("leaving family {family_head}")
267 }
268 ExecuteMsg::KickFamilyMember { member, .. } => {
269 format!("kicking {member} from family")
270 }
271 ExecuteMsg::CreateFamilyOnBehalf { .. } => "crating node family with".to_string(),
272 ExecuteMsg::JoinFamilyOnBehalf { family_head, .. } => {
273 format!("joining family {family_head}")
274 }
275 ExecuteMsg::LeaveFamilyOnBehalf { family_head, .. } => {
276 format!("leaving family {family_head}")
277 }
278 ExecuteMsg::KickFamilyMemberOnBehalf { member, .. } => {
279 format!("kicking {member} from family")
280 }
281 ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
282 format!("updating rewarding validator to {address}")
283 }
284 ExecuteMsg::UpdateContractStateParams { .. } => {
285 "updating mixnet state parameters".into()
286 }
287 ExecuteMsg::UpdateActiveSetSize {
288 active_set_size,
289 force_immediately,
290 } => format!(
291 "updating active set size to {active_set_size}. forced: {force_immediately}"
292 ),
293 ExecuteMsg::UpdateRewardingParams {
294 force_immediately, ..
295 } => format!("updating mixnet rewarding parameters. forced: {force_immediately}"),
296 ExecuteMsg::UpdateIntervalConfig {
297 force_immediately, ..
298 } => format!("updating mixnet interval configuration. forced: {force_immediately}"),
299 ExecuteMsg::BeginEpochTransition {} => "beginning epoch transition".into(),
300 ExecuteMsg::AdvanceCurrentEpoch { .. } => "advancing current epoch".into(),
301 ExecuteMsg::ReconcileEpochEvents { .. } => "reconciling epoch events".into(),
302 ExecuteMsg::BondMixnode { mix_node, .. } => {
303 format!("bonding mixnode {}", mix_node.identity_key)
304 }
305 ExecuteMsg::BondMixnodeOnBehalf { mix_node, .. } => {
306 format!("bonding mixnode {} on behalf", mix_node.identity_key)
307 }
308 ExecuteMsg::PledgeMore {} => "pledging additional tokens".into(),
309 ExecuteMsg::PledgeMoreOnBehalf { .. } => "pledging additional tokens on behalf".into(),
310 ExecuteMsg::DecreasePledge { .. } => "decreasing mixnode pledge".into(),
311 ExecuteMsg::DecreasePledgeOnBehalf { .. } => {
312 "decreasing mixnode pledge on behalf".into()
313 }
314 ExecuteMsg::UnbondMixnode { .. } => "unbonding mixnode".into(),
315 ExecuteMsg::UnbondMixnodeOnBehalf { .. } => "unbonding mixnode on behalf".into(),
316 ExecuteMsg::UpdateMixnodeCostParams { .. } => "updating mixnode cost parameters".into(),
317 ExecuteMsg::UpdateMixnodeCostParamsOnBehalf { .. } => {
318 "updating mixnode cost parameters on behalf".into()
319 }
320 ExecuteMsg::UpdateMixnodeConfig { .. } => "updating mixnode configuration".into(),
321 ExecuteMsg::UpdateMixnodeConfigOnBehalf { .. } => {
322 "updating mixnode configuration on behalf".into()
323 }
324 ExecuteMsg::BondGateway { gateway, .. } => {
325 format!("bonding gateway {}", gateway.identity_key)
326 }
327 ExecuteMsg::BondGatewayOnBehalf { gateway, .. } => {
328 format!("bonding gateway {} on behalf", gateway.identity_key)
329 }
330 ExecuteMsg::UnbondGateway { .. } => "unbonding gateway".into(),
331 ExecuteMsg::UnbondGatewayOnBehalf { .. } => "unbonding gateway on behalf".into(),
332 ExecuteMsg::UpdateGatewayConfig { .. } => "updating gateway configuration".into(),
333 ExecuteMsg::UpdateGatewayConfigOnBehalf { .. } => {
334 "updating gateway configuration on behalf".into()
335 }
336 ExecuteMsg::DelegateToMixnode { mix_id } => format!("delegating to mixnode {mix_id}"),
337 ExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, .. } => {
338 format!("delegating to mixnode {mix_id} on behalf")
339 }
340 ExecuteMsg::UndelegateFromMixnode { mix_id } => {
341 format!("removing delegation from mixnode {mix_id}")
342 }
343 ExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, .. } => {
344 format!("removing delegation from mixnode {mix_id} on behalf")
345 }
346 ExecuteMsg::RewardMixnode {
347 mix_id,
348 performance,
349 } => format!("rewarding mixnode {mix_id} for performance {performance}"),
350 ExecuteMsg::WithdrawOperatorReward { .. } => "withdrawing operator reward".into(),
351 ExecuteMsg::WithdrawOperatorRewardOnBehalf { .. } => {
352 "withdrawing operator reward on behalf".into()
353 }
354 ExecuteMsg::WithdrawDelegatorReward { mix_id } => {
355 format!("withdrawing delegator reward from mixnode {mix_id}")
356 }
357 ExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, .. } => {
358 format!("withdrawing delegator reward from mixnode {mix_id} on behalf")
359 }
360 #[cfg(feature = "contract-testing")]
361 ExecuteMsg::TestingResolveAllPendingEvents { .. } => {
362 "resolving all pending events".into()
363 }
364 }
365 }
366}
367
368#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
369#[serde(rename_all = "snake_case")]
370pub enum QueryMsg {
371 GetAllFamiliesPaged {
373 limit: Option<u32>,
374 start_after: Option<String>,
375 },
376 GetAllMembersPaged {
377 limit: Option<u32>,
378 start_after: Option<String>,
379 },
380 GetFamilyByHead {
381 head: String,
382 },
383 GetFamilyByLabel {
384 label: String,
385 },
386 GetFamilyMembersByHead {
387 head: String,
388 },
389 GetFamilyMembersByLabel {
390 label: String,
391 },
392 GetContractVersion {},
394 #[serde(rename = "get_cw2_contract_version")]
395 GetCW2ContractVersion {},
396 GetRewardingValidatorAddress {},
397 GetStateParams {},
398 GetState {},
399 GetRewardingParams {},
400 GetEpochStatus {},
401 GetCurrentIntervalDetails {},
402 GetRewardedSet {
403 limit: Option<u32>,
404 start_after: Option<MixId>,
405 },
406
407 GetMixNodeBonds {
409 limit: Option<u32>,
410 start_after: Option<MixId>,
411 },
412 GetMixNodesDetailed {
413 limit: Option<u32>,
414 start_after: Option<MixId>,
415 },
416 GetUnbondedMixNodes {
417 limit: Option<u32>,
418 start_after: Option<MixId>,
419 },
420 GetUnbondedMixNodesByOwner {
421 owner: String,
422 limit: Option<u32>,
423 start_after: Option<MixId>,
424 },
425 GetUnbondedMixNodesByIdentityKey {
426 identity_key: String,
427 limit: Option<u32>,
428 start_after: Option<MixId>,
429 },
430 GetOwnedMixnode {
431 address: String,
432 },
433 GetMixnodeDetails {
434 mix_id: MixId,
435 },
436 GetMixnodeRewardingDetails {
437 mix_id: MixId,
438 },
439 GetStakeSaturation {
440 mix_id: MixId,
441 },
442 GetUnbondedMixNodeInformation {
443 mix_id: MixId,
444 },
445 GetBondedMixnodeDetailsByIdentity {
446 mix_identity: IdentityKey,
447 },
448 GetLayerDistribution {},
449 GetGateways {
451 start_after: Option<IdentityKey>,
452 limit: Option<u32>,
453 },
454 GetGatewayBond {
455 identity: IdentityKey,
456 },
457 GetOwnedGateway {
458 address: String,
459 },
460
461 GetMixnodeDelegations {
464 mix_id: MixId,
465 start_after: Option<String>,
468 limit: Option<u32>,
469 },
470 GetDelegatorDelegations {
472 delegator: String,
475 start_after: Option<(MixId, OwnerProxySubKey)>,
476 limit: Option<u32>,
477 },
478 GetDelegationDetails {
480 mix_id: MixId,
481 delegator: String,
482 proxy: Option<String>,
483 },
484 GetAllDelegations {
486 start_after: Option<delegation::StorageKey>,
487 limit: Option<u32>,
488 },
489
490 GetPendingOperatorReward {
492 address: String,
493 },
494 GetPendingMixNodeOperatorReward {
495 mix_id: MixId,
496 },
497 GetPendingDelegatorReward {
498 address: String,
499 mix_id: MixId,
500 proxy: Option<String>,
501 },
502 GetEstimatedCurrentEpochOperatorReward {
504 mix_id: MixId,
505 estimated_performance: Performance,
506 },
507 GetEstimatedCurrentEpochDelegatorReward {
508 address: String,
509 mix_id: MixId,
510 proxy: Option<String>,
511 estimated_performance: Performance,
512 },
513
514 GetPendingEpochEvents {
516 limit: Option<u32>,
517 start_after: Option<u32>,
518 },
519 GetPendingIntervalEvents {
520 limit: Option<u32>,
521 start_after: Option<u32>,
522 },
523 GetPendingEpochEvent {
524 event_id: EpochEventId,
525 },
526 GetPendingIntervalEvent {
527 event_id: IntervalEventId,
528 },
529 GetNumberOfPendingEvents {},
530
531 GetSigningNonce {
533 address: String,
534 },
535}
536
537#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
538#[serde(rename_all = "snake_case")]
539pub struct MigrateMsg {
540 pub vesting_contract_address: Option<String>,
541}