df_hyperliquid_core/trade/margin/
leverage.rs1use crate::markets::perps::meta::PerpAsset;
6use crate::trade::error::TradeError;
7use crate::trade::margin::tables::{LeverageError, MarginTable, checked_leverage};
8use crate::trade::ticket::{Market, Refusal};
9use crate::utils::sign::{L1Action, Map};
10use crate::utils::{Asset, Dec};
11
12pub use crate::account::holdings::MarginMode;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct UpdateLeverage {
18 asset: Asset,
19 mode: MarginMode,
20 leverage: u32,
21}
22
23impl UpdateLeverage {
24 pub fn new(asset: Asset, mode: MarginMode, leverage: u32) -> Result<UpdateLeverage, TradeError> {
27 match leverage {
28 0 => Err(TradeError::NoLeverage),
29 leverage => Ok(UpdateLeverage { asset, mode, leverage }),
30 }
31 }
32
33 #[must_use]
34 pub const fn leverage(&self) -> u32 {
35 self.leverage
36 }
37
38 #[must_use]
39 pub const fn mode(&self) -> MarginMode {
40 self.mode
41 }
42}
43
44impl L1Action for UpdateLeverage {
45 fn action(&self) -> Map {
46 Map::new()
47 .put("type", "updateLeverage")
48 .put("asset", self.asset)
49 .put("isCross", matches!(self.mode, MarginMode::Cross))
50 .put("leverage", self.leverage)
51 }
52}
53
54pub fn update_leverage(
57 asset: Asset,
58 perp: &PerpAsset,
59 mode: MarginMode,
60 leverage: u32,
61) -> Result<UpdateLeverage, LeverageError> {
62 checked_leverage(asset, &perp.name, perp.max_leverage, perp.allows_cross(), mode, leverage)
63}
64
65pub fn update_leverage_for(
69 asset: Asset,
70 perp: &PerpAsset,
71 table: &MarginTable,
72 mode: MarginMode,
73 leverage: u32,
74 notional: Dec,
75) -> Result<UpdateLeverage, LeverageError> {
76 let set = update_leverage(asset, perp, mode, leverage)?;
77 table.check(&perp.name, leverage, notional)?;
78 Ok(set)
79}
80
81pub fn leverage(market: &Market, mode: MarginMode, leverage: u32) -> Result<UpdateLeverage, Refusal> {
83 let Some(most) = market.max_leverage() else {
84 return Err(Refusal::Spot("leverage"));
85 };
86 checked_leverage(market.asset(), "", most, market.allows_cross(), mode, leverage).map_err(|error| match error {
88 LeverageError::TooHigh { .. }
89 | LeverageError::OverTier { .. }
90 | LeverageError::Trade(TradeError::NoLeverage) => Refusal::Leverage { asked: leverage, most },
91 LeverageError::NoCross(_) => Refusal::IsolatedOnly,
92 LeverageError::Trade(error) => Refusal::Trade(error),
93 })
94}
95
96#[cfg(test)]
97#[path = "tests/leverage.rs"]
98mod tests;