hotmint_staking/types.rs
1use serde::{Deserialize, Serialize};
2
3use hotmint_types::crypto::PublicKey;
4use hotmint_types::validator::ValidatorId;
5
6/// Validator state within the staking system.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ValidatorState {
9 pub id: ValidatorId,
10 pub public_key: PublicKey,
11 /// Self-bonded stake.
12 pub self_stake: u64,
13 /// Total delegated stake from other stakers.
14 pub delegated_stake: u64,
15 /// Reputation score (0 to `config.max_score`).
16 pub score: u32,
17 /// Whether the validator is jailed (temporarily removed from active set).
18 pub jailed: bool,
19 /// Block height until which the validator remains jailed.
20 pub jail_until_height: u64,
21}
22
23impl ValidatorState {
24 /// Total stake = self-bonded + delegated.
25 pub fn total_stake(&self) -> u64 {
26 self.self_stake.saturating_add(self.delegated_stake)
27 }
28
29 /// Voting power: total stake if not jailed, 0 otherwise.
30 pub fn voting_power(&self) -> u64 {
31 if self.jailed { 0 } else { self.total_stake() }
32 }
33}
34
35/// A single delegation entry from a staker to a validator.
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct StakeEntry {
38 pub amount: u64,
39}
40
41/// Reason for slashing a validator.
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum SlashReason {
44 /// Equivocation (double-signing).
45 DoubleSign,
46 /// Extended downtime / inactivity.
47 Downtime,
48}
49
50/// Result of a slash operation.
51#[derive(Debug, Clone)]
52pub struct SlashResult {
53 /// Amount slashed from self-stake.
54 pub self_slashed: u64,
55 /// Amount slashed from delegated stakes.
56 pub delegated_slashed: u64,
57 /// Whether the validator was jailed.
58 pub jailed: bool,
59}
60
61/// An entry in the unbonding queue.
62///
63/// When a delegator undelegates, voting power is reduced immediately but
64/// the tokens are locked until `completion_height` to prevent slash evasion.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct UnbondingEntry {
67 pub staker: Vec<u8>,
68 pub validator: ValidatorId,
69 pub amount: u64,
70 /// Block height at which the unbonding completes.
71 pub completion_height: u64,
72}
73
74/// Staking system configuration.
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct StakingConfig {
77 /// Maximum number of active (non-jailed) validators in the formal set.
78 pub max_validators: usize,
79 /// Minimum self-stake required to register as a validator.
80 pub min_self_stake: u64,
81 /// Slash rate for double-signing (basis points: 500 = 5%).
82 pub slash_rate_double_sign: u32,
83 /// Slash rate for downtime (basis points: 100 = 1%).
84 pub slash_rate_downtime: u32,
85 /// Number of blocks a jailed validator must wait before unjailing.
86 pub jail_duration: u64,
87 /// Initial reputation score for new validators.
88 pub initial_score: u32,
89 /// Maximum reputation score.
90 pub max_score: u32,
91 /// Block reward (added to proposer's self-stake).
92 pub block_reward: u64,
93 /// Unbonding period in blocks. 0 = instant (legacy behavior).
94 pub unbonding_period: u64,
95}
96
97impl Default for StakingConfig {
98 fn default() -> Self {
99 Self {
100 max_validators: 100,
101 min_self_stake: 1000,
102 slash_rate_double_sign: 500, // 5%
103 slash_rate_downtime: 100, // 1%
104 jail_duration: 1000,
105 initial_score: 10_000,
106 max_score: 10_000,
107 block_reward: 100,
108 unbonding_period: 1000,
109 }
110 }
111}