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