sui_types/
governance.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_core_types::ident_str;
5use move_core_types::identifier::IdentStr;
6use move_core_types::language_storage::StructTag;
7
8use crate::SUI_SYSTEM_ADDRESS;
9use crate::balance::Balance;
10use crate::base_types::ObjectID;
11use crate::committee::EpochId;
12use crate::error::{SuiError, SuiErrorKind};
13use crate::gas_coin::MIST_PER_SUI;
14use crate::id::{ID, UID};
15use crate::object::{Data, Object};
16use serde::Deserialize;
17use serde::Serialize;
18
19// === Pre SIP-39 Constants ===
20
21/// Maximum number of active validators at any moment.
22/// We do not allow the number of validators in any epoch to go above this.
23pub const MAX_VALIDATOR_COUNT: u64 = 150;
24
25#[deprecated(note = "SIP-39 removes min barreier for joining the validator set")]
26/// Lower-bound on the amount of stake required to become a validator.
27///
28/// 30 million SUI
29pub const MIN_VALIDATOR_JOINING_STAKE_MIST: u64 = 30_000_000 * MIST_PER_SUI;
30
31#[deprecated(note = "SIP-39 removes low barreier for joining the validator set")]
32/// Deprecated: with SIP-39 there is no longer a minimum stake requirement.
33///
34/// Validators with stake amount below `validator_low_stake_threshold` are considered to
35/// have low stake and will be escorted out of the validator set after being below this
36/// threshold for more than `validator_low_stake_grace_period` number of epochs.
37///
38/// 20 million SUI
39pub const VALIDATOR_LOW_STAKE_THRESHOLD_MIST: u64 = 20_000_000 * MIST_PER_SUI;
40
41#[deprecated(note = "SIP-39 removes very low barreier for joining the validator set")]
42/// Validators with stake below `validator_very_low_stake_threshold` will be removed
43/// immediately at epoch change, no grace period.
44///
45/// 15 million SUI
46pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MIST: u64 = 15_000_000 * MIST_PER_SUI;
47
48/// Number of epochs for a single phase of SIP-39 since the change
49pub const SIP_39_PHASE_LENGTH: u64 = 14;
50
51// === Post SIP-39 (Phase 1) ===
52
53/// Minimum amount of voting power required to become a validator in Phase 1.
54/// .12% of voting power
55pub const VALIDATOR_MIN_POWER_PHASE_1: u64 = 12;
56
57/// Low voting power threshold for validators in Phase 1.
58/// Validators below this threshold fall into the "at risk" group.
59/// .08% of voting power
60pub const VALIDATOR_LOW_POWER_PHASE_1: u64 = 8;
61
62/// Very low voting power threshold for validators in Phase 1.
63/// Validators below this threshold will be removed immediately at epoch change.
64/// .04% of voting power
65pub const VALIDATOR_VERY_LOW_POWER_PHASE_1: u64 = 4;
66
67// === Post SIP-39 (Phase 2) ===
68
69/// Minimum amount of voting power required to become a validator in Phase 2.
70/// .12% of voting power
71pub const VALIDATOR_MIN_POWER_PHASE_2: u64 = 6;
72
73/// Low voting power threshold for validators in Phase 2.
74/// Validators below this threshold fall into the "at risk" group.
75/// .08% of voting power
76pub const VALIDATOR_LOW_POWER_PHASE_2: u64 = 4;
77
78/// Very low voting power threshold for validators in Phase 2.
79/// Validators below this threshold will be removed immediately at epoch change.
80/// .04% of voting power
81pub const VALIDATOR_VERY_LOW_POWER_PHASE_2: u64 = 2;
82
83// === Post SIP-39 (Phase 3) ===
84
85/// Minimum amount of voting power required to become a validator in Phase 3.
86/// .03% of voting power
87pub const VALIDATOR_MIN_POWER_PHASE_3: u64 = 3;
88
89/// Low voting power threshold for validators in Phase 3.
90/// Validators below this threshold fall into the "at risk" group.
91/// .02% of voting power
92pub const VALIDATOR_LOW_POWER_PHASE_3: u64 = 2;
93
94/// Very low voting power threshold for validators in Phase 3.
95/// Validators below this threshold will be removed immediately at epoch change.
96/// .01% of voting power
97pub const VALIDATOR_VERY_LOW_POWER_PHASE_3: u64 = 1;
98
99/// A validator can have stake below `validator_low_stake_threshold`
100/// for this many epochs before being kicked out.
101pub const VALIDATOR_LOW_STAKE_GRACE_PERIOD: u64 = 7;
102
103pub const STAKING_POOL_MODULE_NAME: &IdentStr = ident_str!("staking_pool");
104pub const STAKED_SUI_STRUCT_NAME: &IdentStr = ident_str!("StakedSui");
105
106pub const ADD_STAKE_MUL_COIN_FUN_NAME: &IdentStr = ident_str!("request_add_stake_mul_coin");
107pub const ADD_STAKE_FUN_NAME: &IdentStr = ident_str!("request_add_stake");
108pub const WITHDRAW_STAKE_FUN_NAME: &IdentStr = ident_str!("request_withdraw_stake");
109
110#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
111pub struct StakedSui {
112    id: UID,
113    pool_id: ID,
114    stake_activation_epoch: u64,
115    principal: Balance,
116}
117
118impl StakedSui {
119    pub fn type_() -> StructTag {
120        StructTag {
121            address: SUI_SYSTEM_ADDRESS,
122            module: STAKING_POOL_MODULE_NAME.to_owned(),
123            name: STAKED_SUI_STRUCT_NAME.to_owned(),
124            type_params: vec![],
125        }
126    }
127
128    pub fn is_staked_sui(s: &StructTag) -> bool {
129        s.address == SUI_SYSTEM_ADDRESS
130            && s.module.as_ident_str() == STAKING_POOL_MODULE_NAME
131            && s.name.as_ident_str() == STAKED_SUI_STRUCT_NAME
132            && s.type_params.is_empty()
133    }
134
135    pub fn id(&self) -> ObjectID {
136        self.id.id.bytes
137    }
138
139    pub fn pool_id(&self) -> ObjectID {
140        self.pool_id.bytes
141    }
142
143    pub fn activation_epoch(&self) -> EpochId {
144        self.stake_activation_epoch
145    }
146
147    pub fn request_epoch(&self) -> EpochId {
148        // TODO: this might change when we implement warm up period.
149        self.stake_activation_epoch.saturating_sub(1)
150    }
151
152    pub fn principal(&self) -> u64 {
153        self.principal.value()
154    }
155}
156
157impl TryFrom<&Object> for StakedSui {
158    type Error = SuiError;
159    fn try_from(object: &Object) -> Result<Self, Self::Error> {
160        match &object.data {
161            Data::Move(o) => {
162                if o.type_().is_staked_sui() {
163                    return bcs::from_bytes(o.contents()).map_err(|err| {
164                        SuiErrorKind::TypeError {
165                            error: format!("Unable to deserialize StakedSui object: {:?}", err),
166                        }
167                        .into()
168                    });
169                }
170            }
171            Data::Package(_) => {}
172        }
173
174        Err(SuiErrorKind::TypeError {
175            error: format!("Object type is not a StakedSui: {:?}", object),
176        }
177        .into())
178    }
179}