1use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag};
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 IOTA_SYSTEM_ADDRESS,
10 balance::Balance,
11 base_types::ObjectID,
12 committee::EpochId,
13 error::IotaError,
14 gas_coin::NANOS_PER_IOTA,
15 id::{ID, UID},
16 object::{Data, Object},
17};
18
19pub const MAX_VALIDATOR_COUNT: u64 = 150;
22
23pub const MIN_VALIDATOR_JOINING_STAKE_NANOS: u64 = 2_000_000 * NANOS_PER_IOTA;
27
28pub const VALIDATOR_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_500_000 * NANOS_PER_IOTA;
35
36pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_000_000 * NANOS_PER_IOTA;
41
42pub const VALIDATOR_LOW_STAKE_GRACE_PERIOD: u64 = 7;
45
46pub const STAKING_POOL_MODULE_NAME: &IdentStr = ident_str!("staking_pool");
47pub const STAKED_IOTA_STRUCT_NAME: &IdentStr = ident_str!("StakedIota");
48
49pub const ADD_STAKE_MUL_COIN_FUN_NAME: &IdentStr = ident_str!("request_add_stake_mul_coin");
50pub const ADD_STAKE_FUN_NAME: &IdentStr = ident_str!("request_add_stake");
51pub const WITHDRAW_STAKE_FUN_NAME: &IdentStr = ident_str!("request_withdraw_stake");
52
53#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
54pub struct StakedIota {
55 id: UID,
56 pool_id: ID,
57 stake_activation_epoch: u64,
58 principal: Balance,
59}
60
61impl StakedIota {
62 pub fn type_() -> StructTag {
63 StructTag {
64 address: IOTA_SYSTEM_ADDRESS,
65 module: STAKING_POOL_MODULE_NAME.to_owned(),
66 name: STAKED_IOTA_STRUCT_NAME.to_owned(),
67 type_params: vec![],
68 }
69 }
70
71 pub fn is_staked_iota(s: &StructTag) -> bool {
72 s.address == IOTA_SYSTEM_ADDRESS
73 && s.module.as_ident_str() == STAKING_POOL_MODULE_NAME
74 && s.name.as_ident_str() == STAKED_IOTA_STRUCT_NAME
75 && s.type_params.is_empty()
76 }
77
78 pub fn id(&self) -> ObjectID {
79 self.id.id.bytes
80 }
81
82 pub fn pool_id(&self) -> ObjectID {
83 self.pool_id.bytes
84 }
85
86 pub fn activation_epoch(&self) -> EpochId {
87 self.stake_activation_epoch
88 }
89
90 pub fn request_epoch(&self) -> EpochId {
91 self.stake_activation_epoch.saturating_sub(1)
93 }
94
95 pub fn principal(&self) -> u64 {
96 self.principal.value()
97 }
98}
99
100impl TryFrom<&Object> for StakedIota {
101 type Error = IotaError;
102 fn try_from(object: &Object) -> Result<Self, Self::Error> {
103 match &object.data {
104 Data::Move(o) => {
105 if o.type_().is_staked_iota() {
106 return bcs::from_bytes(o.contents()).map_err(|err| IotaError::Type {
107 error: format!("Unable to deserialize StakedIota object: {:?}", err),
108 });
109 }
110 }
111 Data::Package(_) => {}
112 }
113
114 Err(IotaError::Type {
115 error: format!("Object type is not a StakedIota: {:?}", object),
116 })
117 }
118}