Skip to main content

df_hyperliquid_core/utils/sign/
msgpack.rs

1//! Msgpack as the venue hashes an L1 action: map keys in insertion order,
2//! never sorted, and a non-negative integer always unsigned.
3
4use std::borrow::Cow;
5
6use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
7
8use crate::utils::json::Json;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum Value {
12    Nil,
13    Bool(bool),
14    Uint(u64),
15    /// A negative integer. Non-negative values still encode as unsigned.
16    Int(i64),
17    Str(Cow<'static, str>),
18    Array(Vec<Value>),
19    Map(Map),
20}
21
22impl Value {
23    #[must_use]
24    pub fn array<V: Into<Value>>(items: impl IntoIterator<Item = V>) -> Value {
25        Value::Array(items.into_iter().map(Into::into).collect())
26    }
27
28    #[must_use]
29    pub fn to_msgpack(&self) -> Vec<u8> {
30        encode(self)
31    }
32
33    /// The same tree as JSON, keys in the same order: what is posted is what
34    /// was hashed.
35    #[must_use]
36    pub fn to_json(&self) -> Json {
37        match self {
38            Value::Nil => Json::Null,
39            Value::Bool(value) => Json::Bool(*value),
40            Value::Uint(number) => Json::Number(number.to_string()),
41            Value::Int(number) => Json::Number(number.to_string()),
42            Value::Str(text) => Json::String(text.to_string()),
43            Value::Array(items) => Json::Array(items.iter().map(Value::to_json).collect()),
44            Value::Map(map) => map.to_json(),
45        }
46    }
47}
48
49/// An ordered msgpack map: a list of key/value pairs in wire order.
50#[derive(Debug, Clone, PartialEq, Eq, Default)]
51pub struct Map(Vec<(Cow<'static, str>, Value)>);
52
53impl Map {
54    #[must_use]
55    pub const fn new() -> Self {
56        Map(Vec::new())
57    }
58
59    #[must_use]
60    pub fn put(mut self, key: impl Into<Cow<'static, str>>, value: impl Into<Value>) -> Self {
61        self.0.push((key.into(), value.into()));
62        self
63    }
64
65    #[must_use]
66    pub fn put_some(self, key: impl Into<Cow<'static, str>>, value: Option<impl Into<Value>>) -> Self {
67        match value {
68            Some(value) => self.put(key, value),
69            None => self,
70        }
71    }
72
73    #[must_use]
74    pub fn len(&self) -> usize {
75        self.0.len()
76    }
77
78    #[must_use]
79    pub fn is_empty(&self) -> bool {
80        self.0.is_empty()
81    }
82
83    /// The pairs themselves, in wire order, for splicing one map into another.
84    pub fn into_pairs(self) -> impl Iterator<Item = (Cow<'static, str>, Value)> {
85        self.0.into_iter()
86    }
87
88    pub fn keys(&self) -> impl Iterator<Item = &str> {
89        self.0.iter().map(|(key, _)| key.as_ref())
90    }
91
92    #[must_use]
93    pub fn get(&self, key: &str) -> Option<&Value> {
94        self.0.iter().find(|(stored, _)| stored == key).map(|(_, value)| value)
95    }
96
97    #[must_use]
98    pub fn to_msgpack(&self) -> Vec<u8> {
99        let mut out = Vec::new();
100        write_map(self, &mut out);
101        out
102    }
103
104    #[must_use]
105    pub fn to_json(&self) -> Json {
106        Json::Object(self.0.iter().map(|(key, value)| (key.to_string(), value.to_json())).collect())
107    }
108}
109
110impl From<Map> for Value {
111    fn from(map: Map) -> Value {
112        Value::Map(map)
113    }
114}
115
116impl From<bool> for Value {
117    fn from(value: bool) -> Value {
118        Value::Bool(value)
119    }
120}
121
122impl From<u64> for Value {
123    fn from(value: u64) -> Value {
124        Value::Uint(value)
125    }
126}
127
128impl From<u32> for Value {
129    fn from(value: u32) -> Value {
130        Value::Uint(u64::from(value))
131    }
132}
133
134impl From<i64> for Value {
135    fn from(value: i64) -> Value {
136        Value::Int(value)
137    }
138}
139
140impl From<&'static str> for Value {
141    fn from(value: &'static str) -> Value {
142        Value::Str(Cow::Borrowed(value))
143    }
144}
145
146impl From<String> for Value {
147    fn from(value: String) -> Value {
148        Value::Str(Cow::Owned(value))
149    }
150}
151
152impl From<Cow<'static, str>> for Value {
153    fn from(value: Cow<'static, str>) -> Value {
154        Value::Str(value)
155    }
156}
157
158impl From<Vec<Value>> for Value {
159    fn from(value: Vec<Value>) -> Value {
160        Value::Array(value)
161    }
162}
163
164#[must_use]
165pub fn encode(value: &Value) -> Vec<u8> {
166    let mut out = Vec::new();
167    write(value, &mut out);
168    out
169}
170
171pub fn write(value: &Value, out: &mut Vec<u8>) {
172    match value {
173        Value::Nil => out.push(0xc0),
174        Value::Bool(false) => out.push(0xc2),
175        Value::Bool(true) => out.push(0xc3),
176        Value::Uint(number) => write_uint(*number, out),
177        Value::Int(number) => write_int(*number, out),
178        Value::Str(text) => write_str(text, out),
179        Value::Array(items) => {
180            write_len(items.len(), 0x90, 0xdc, 0xdd, out);
181            for item in items {
182                write(item, out);
183            }
184        }
185        Value::Map(map) => write_map(map, out),
186    }
187}
188
189fn write_map(map: &Map, out: &mut Vec<u8>) {
190    write_len(map.0.len(), 0x80, 0xde, 0xdf, out);
191    for (key, value) in &map.0 {
192        write_str(key, out);
193        write(value, out);
194    }
195}
196
197fn write_len(len: usize, fixed: u8, wide16: u8, wide32: u8, out: &mut Vec<u8>) {
198    if len <= 15 {
199        out.push(fixed | len as u8);
200    } else if let Ok(len) = u16::try_from(len) {
201        out.push(wide16);
202        out.extend_from_slice(&len.to_be_bytes());
203    } else {
204        out.push(wide32);
205        out.extend_from_slice(&(len as u32).to_be_bytes());
206    }
207}
208
209fn write_str(text: &str, out: &mut Vec<u8>) {
210    let bytes = text.as_bytes();
211    if bytes.len() <= 31 {
212        out.push(0xa0 | bytes.len() as u8);
213    } else if let Ok(len) = u8::try_from(bytes.len()) {
214        out.push(0xd9);
215        out.push(len);
216    } else if let Ok(len) = u16::try_from(bytes.len()) {
217        out.push(0xda);
218        out.extend_from_slice(&len.to_be_bytes());
219    } else {
220        out.push(0xdb);
221        out.extend_from_slice(&(bytes.len() as u32).to_be_bytes());
222    }
223    out.extend_from_slice(bytes);
224}
225
226fn write_uint(number: u64, out: &mut Vec<u8>) {
227    if number <= 0x7f {
228        out.push(number as u8);
229    } else if let Ok(byte) = u8::try_from(number) {
230        out.push(0xcc);
231        out.push(byte);
232    } else if let Ok(short) = u16::try_from(number) {
233        out.push(0xcd);
234        out.extend_from_slice(&short.to_be_bytes());
235    } else if let Ok(word) = u32::try_from(number) {
236        out.push(0xce);
237        out.extend_from_slice(&word.to_be_bytes());
238    } else {
239        out.push(0xcf);
240        out.extend_from_slice(&number.to_be_bytes());
241    }
242}
243
244fn write_int(number: i64, out: &mut Vec<u8>) {
245    if let Ok(unsigned) = u64::try_from(number) {
246        write_uint(unsigned, out);
247    } else if number >= -32 {
248        out.push(number as u8);
249    } else if let Ok(byte) = i8::try_from(number) {
250        out.push(0xd0);
251        out.extend_from_slice(&byte.to_be_bytes());
252    } else if let Ok(short) = i16::try_from(number) {
253        out.push(0xd1);
254        out.extend_from_slice(&short.to_be_bytes());
255    } else if let Ok(word) = i32::try_from(number) {
256        out.push(0xd2);
257        out.extend_from_slice(&word.to_be_bytes());
258    } else {
259        out.push(0xd3);
260        out.extend_from_slice(&number.to_be_bytes());
261    }
262}
263
264impl Serialize for Value {
265    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
266        match self {
267            Value::Nil => serializer.serialize_unit(),
268            Value::Bool(value) => serializer.serialize_bool(*value),
269            Value::Uint(number) => serializer.serialize_u64(*number),
270            Value::Int(number) => serializer.serialize_i64(*number),
271            Value::Str(text) => serializer.serialize_str(text),
272            Value::Array(items) => {
273                let mut sequence = serializer.serialize_seq(Some(items.len()))?;
274                for item in items {
275                    sequence.serialize_element(item)?;
276                }
277                sequence.end()
278            }
279            Value::Map(map) => map.serialize(serializer),
280        }
281    }
282}
283
284impl Serialize for Map {
285    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
286        let mut entries = serializer.serialize_map(Some(self.0.len()))?;
287        for (key, value) in &self.0 {
288            entries.serialize_entry(key.as_ref(), value)?;
289        }
290        entries.end()
291    }
292}
293
294#[cfg(test)]
295#[path = "tests/msgpack.rs"]
296mod tests;