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