Skip to main content

df_hyperliquid_core/trade/outcomes/
split.rs

1//! `userOutcome`: an account turning quote tokens into one of each side of
2//! an outcome, and back. Both may act for a subaccount through the body's
3//! `vaultAddress`, which the hash covers.
4
5use crate::markets::outcomes::error::OutcomeError;
6use crate::utils::Dec;
7use crate::utils::sign::{L1Action, Map, Value};
8
9/// The most places a quote amount may have.
10pub const MAX_AMOUNT_PLACES: u32 = 8;
11
12fn amount(value: Dec) -> Result<Dec, OutcomeError> {
13    match value.is_positive() && value.places() <= MAX_AMOUNT_PLACES {
14        true => Ok(value),
15        false => Err(OutcomeError::Amount(value)),
16    }
17}
18
19/// `{"type":"userOutcome","splitOutcome":{"outcome","amount"}}`: `amount` of
20/// the quote token into that many of each side. The amount goes as a decimal
21/// with no trailing zeros, so `12.50` and `12.5` are one action.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct SplitOutcome {
24    outcome: u32,
25    amount: Dec,
26}
27
28impl SplitOutcome {
29    pub fn new(outcome: u32, amount_of_quote: Dec) -> Result<SplitOutcome, OutcomeError> {
30        Ok(SplitOutcome { outcome, amount: amount(amount_of_quote)? })
31    }
32}
33
34impl L1Action for SplitOutcome {
35    fn action(&self) -> Map {
36        Map::new()
37            .put("type", "userOutcome")
38            .put("splitOutcome", Map::new().put("outcome", self.outcome).put("amount", self.amount.to_wire()))
39    }
40}
41
42/// [`SplitOutcome`] undone: as many of each side back into the quote token.
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub struct MergeOutcome {
45    outcome: u32,
46    amount: Option<Dec>,
47}
48
49impl MergeOutcome {
50    pub fn new(outcome: u32, amount_of_quote: Dec) -> Result<MergeOutcome, OutcomeError> {
51        Ok(MergeOutcome { outcome, amount: Some(amount(amount_of_quote)?) })
52    }
53
54    /// Every pair the account holds: the amount goes as nil, not a figure.
55    #[must_use]
56    pub const fn all(outcome: u32) -> MergeOutcome {
57        MergeOutcome { outcome, amount: None }
58    }
59}
60
61impl L1Action for MergeOutcome {
62    fn action(&self) -> Map {
63        let amount = match self.amount {
64            Some(amount) => Value::from(amount.to_wire()),
65            None => Value::Nil,
66        };
67        Map::new()
68            .put("type", "userOutcome")
69            .put("mergeOutcome", Map::new().put("outcome", self.outcome).put("amount", amount))
70    }
71}
72
73#[cfg(test)]
74#[path = "tests/split.rs"]
75mod tests;