Skip to main content

metaflux_client/types/
mod.rs

1//! Domain types shared by all transports.
2//!
3//! Types use `#[serde(rename_all = "snake_case")]` to match the wire
4//! convention. Sizes / prices / ids are plain-integer fields on fixed-point
5//! planes; fractional magnitudes (margin deltas, stake, vault amounts) ride the
6//! wire as decimal **strings** to preserve precision.
7//!
8//! ## ID newtypes
9//!
10//! Three identifier newtypes are re-exported from this module:
11//!
12//! - [`OrderId`] — server-assigned order identifier (`u64`).
13//! - [`MarketId`] — internal market id (`u32`), sequentially allocated.
14//! - [`VaultId`] — vault id (`u64`), assigned at vault creation.
15
16use serde::{Deserialize, Serialize};
17
18pub mod account;
19pub mod core_evm;
20pub mod cross_chain;
21pub mod encrypted;
22pub mod fba;
23pub mod governance;
24pub mod meta_bridge;
25pub mod order;
26pub mod pm;
27pub mod position;
28pub mod rfq;
29pub mod spot;
30pub mod staking;
31pub mod sub_account;
32pub mod twap;
33pub mod vault;
34
35// ---- ID newtypes ----
36
37/// Server-assigned order identifier.
38///
39/// `0` means "not yet assigned" — the server fills this on accept. The wire
40/// shape is a plain JSON integer.
41#[derive(
42    Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
43)]
44#[serde(transparent)]
45pub struct OrderId(pub u64);
46
47/// Market identifier.
48///
49/// Sequentially allocated; permissionless perp deploys receive fresh ids.
50#[derive(
51    Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
52)]
53#[serde(transparent)]
54pub struct MarketId(pub u32);
55
56/// User-vault identifier.
57///
58/// Assigned by the node at vault creation.
59#[derive(
60    Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
61)]
62#[serde(transparent)]
63pub struct VaultId(pub u64);
64
65/// Client-supplied order identifier (16 bytes / 128 bits) for idempotency.
66///
67/// MTF-native uses `cloid` as a 32-char hex `0x...` string on the wire so it
68/// survives JS-safe-integer limits. We expose it as a `[u8; 16]` newtype
69/// internally and serialize as hex.
70#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
71pub struct Cloid(pub [u8; 16]);
72
73impl Serialize for Cloid {
74    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
75        s.serialize_str(&format!("0x{}", hex::encode(self.0)))
76    }
77}
78
79impl<'de> Deserialize<'de> for Cloid {
80    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
81        let s: String = String::deserialize(d)?;
82        let stripped = s.strip_prefix("0x").unwrap_or(&s);
83        if stripped.len() != 32 {
84            return Err(serde::de::Error::custom(format!(
85                "cloid hex must be 32 chars, got {}",
86                stripped.len()
87            )));
88        }
89        let bytes = hex::decode(stripped).map_err(serde::de::Error::custom)?;
90        let mut out = [0u8; 16];
91        out.copy_from_slice(&bytes);
92        Ok(Self(out))
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn order_id_round_trips_as_plain_integer() {
102        let oid = OrderId(42);
103        let j = serde_json::to_string(&oid).unwrap();
104        assert_eq!(j, "42");
105        let dec: OrderId = serde_json::from_str(&j).unwrap();
106        assert_eq!(oid, dec);
107    }
108
109    #[test]
110    fn market_id_round_trips_as_plain_integer() {
111        let m = MarketId(7);
112        let j = serde_json::to_string(&m).unwrap();
113        assert_eq!(j, "7");
114    }
115
116    #[test]
117    fn cloid_round_trips_as_hex_string() {
118        let cloid = Cloid([0xABu8; 16]);
119        let j = serde_json::to_string(&cloid).unwrap();
120        assert_eq!(j, "\"0xabababababababababababababababab\"");
121        let dec: Cloid = serde_json::from_str(&j).unwrap();
122        assert_eq!(cloid, dec);
123    }
124}