Skip to main content

df_hyperliquid_core/earn/staking/
actions.rs

1//! `cDeposit`, `cWithdraw` and `tokenDelegate`: user-signed, keys in the order
2//! `@nktkas/hyperliquid` 0.33.2 posts them.
3
4use crate::account::signers::ActionKind;
5use crate::earn::staking::plan::Key;
6use crate::utils::sign::{Field, NonceKey, UserAction, UserSigned};
7use crate::utils::{Address, BadUnits, Dec, exact_units};
8
9/// HYPE on Core counts in 1e8: what `wei` means in staking.
10pub const HYPE_DECIMALS: u32 = 8;
11
12/// `hype` as the `wei` an action carries, refused rather than rounded when
13/// it has more than eight places.
14pub fn hype_wei(hype: Dec) -> Result<u64, BadUnits> {
15    exact_units(hype, HYPE_DECIMALS)
16}
17
18/// `cDeposit`: HYPE from spot into the staking balance, undelegated.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct CDeposit {
21    wei: u64,
22    nonce: u64,
23}
24
25impl CDeposit {
26    /// User-signed: only the account's own key.
27    pub const KEY: Key = ActionKind::CDeposit.signers();
28
29    pub fn new(hype: Dec, nonce: u64) -> Result<CDeposit, BadUnits> {
30        Ok(CDeposit { wei: hype_wei(hype)?, nonce })
31    }
32
33    #[must_use]
34    pub const fn wei(&self) -> u64 {
35        self.wei
36    }
37}
38
39impl UserAction for CDeposit {
40    fn user_signed(&self) -> UserSigned<'_> {
41        UserSigned::new("cDeposit", "HyperliquidTransaction:CDeposit", NonceKey::Nonce, self.nonce)
42            .field("wei", Field::Uint64(self.wei))
43    }
44}
45
46/// `cWithdraw`: undelegated HYPE from staking back toward spot, after
47/// [`unstaking_ms`](crate::earn::staking::unstaking_ms) in the queue.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub struct CWithdraw {
50    wei: u64,
51    nonce: u64,
52}
53
54impl CWithdraw {
55    /// User-signed: only the account's own key.
56    pub const KEY: Key = ActionKind::CWithdraw.signers();
57
58    pub fn new(hype: Dec, nonce: u64) -> Result<CWithdraw, BadUnits> {
59        Ok(CWithdraw { wei: hype_wei(hype)?, nonce })
60    }
61
62    #[must_use]
63    pub const fn wei(&self) -> u64 {
64        self.wei
65    }
66}
67
68impl UserAction for CWithdraw {
69    fn user_signed(&self) -> UserSigned<'_> {
70        UserSigned::new("cWithdraw", "HyperliquidTransaction:CWithdraw", NonceKey::Nonce, self.nonce)
71            .field("wei", Field::Uint64(self.wei))
72    }
73}
74
75/// `tokenDelegate`: staking balance to a validator, or back. A delegation is locked for
76/// [`delegation_lock_ms`](crate::earn::staking::delegation_lock_ms) before it can be undelegated.
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct TokenDelegate {
79    validator: Address,
80    wei: u64,
81    is_undelegate: bool,
82    nonce: u64,
83}
84
85impl TokenDelegate {
86    /// User-signed: only the account's own key.
87    pub const KEY: Key = ActionKind::TokenDelegate.signers();
88
89    pub fn delegate(validator: Address, hype: Dec, nonce: u64) -> Result<TokenDelegate, BadUnits> {
90        Ok(TokenDelegate { validator, wei: hype_wei(hype)?, is_undelegate: false, nonce })
91    }
92
93    pub fn undelegate(validator: Address, hype: Dec, nonce: u64) -> Result<TokenDelegate, BadUnits> {
94        Ok(TokenDelegate { validator, wei: hype_wei(hype)?, is_undelegate: true, nonce })
95    }
96
97    #[must_use]
98    pub const fn wei(&self) -> u64 {
99        self.wei
100    }
101}
102
103/// `validator` is an `address` in the typed data, posted lowercase.
104impl UserAction for TokenDelegate {
105    fn user_signed(&self) -> UserSigned<'_> {
106        UserSigned::new("tokenDelegate", "HyperliquidTransaction:TokenDelegate", NonceKey::Nonce, self.nonce)
107            .field("validator", Field::Address(self.validator))
108            .field("wei", Field::Uint64(self.wei))
109            .field("isUndelegate", Field::Bool(self.is_undelegate))
110    }
111}