1use iota_sdk_types::{Identifier, ObjectId};
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 balance::Balance,
10 committee::EpochId,
11 error::IotaError,
12 gas_coin::NANOS_PER_IOTA,
13 id::{ID, UID},
14 object::{Data, Object},
15};
16
17pub const MAX_VALIDATOR_COUNT: u64 = 150;
20
21pub const MIN_VALIDATOR_JOINING_STAKE_NANOS: u64 = 2_000_000 * NANOS_PER_IOTA;
25
26pub const VALIDATOR_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_500_000 * NANOS_PER_IOTA;
33
34pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_000_000 * NANOS_PER_IOTA;
39
40pub const VALIDATOR_LOW_STAKE_GRACE_PERIOD: u64 = 7;
43
44pub const ADD_STAKE_MUL_COIN_FUN_NAME: Identifier =
45 Identifier::from_static("request_add_stake_mul_coin");
46pub const ADD_STAKE_FUN_NAME: Identifier = Identifier::from_static("request_add_stake");
47pub const WITHDRAW_STAKE_FUN_NAME: Identifier = Identifier::from_static("request_withdraw_stake");
48
49#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
50pub struct StakedIota {
51 id: UID,
52 pool_id: ID,
53 stake_activation_epoch: u64,
54 principal: Balance,
55}
56
57impl StakedIota {
58 pub fn id(&self) -> ObjectId {
59 self.id.id.bytes
60 }
61
62 pub fn pool_id(&self) -> ObjectId {
63 self.pool_id.bytes
64 }
65
66 pub fn activation_epoch(&self) -> EpochId {
67 self.stake_activation_epoch
68 }
69
70 pub fn request_epoch(&self) -> EpochId {
71 self.stake_activation_epoch.saturating_sub(1)
73 }
74
75 pub fn principal(&self) -> u64 {
76 self.principal.value()
77 }
78}
79
80impl TryFrom<&Object> for StakedIota {
81 type Error = IotaError;
82 fn try_from(object: &Object) -> Result<Self, Self::Error> {
83 match &object.data {
84 Data::Struct(o) => {
85 if o.struct_tag().is_staked_iota() {
86 return bcs::from_bytes(o.contents()).map_err(|err| IotaError::Type {
87 error: format!("Unable to deserialize StakedIota object: {err:?}"),
88 });
89 }
90 }
91 Data::Package(_) => {}
92 }
93
94 Err(IotaError::Type {
95 error: format!("Object type is not a StakedIota: {object:?}"),
96 })
97 }
98}