hyperliquid/
types.rs

1use crate::utils::as_hex;
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
6#[serde(rename_all = "PascalCase")]
7pub enum Chain {
8    Dev = 1337,
9
10    Arbitrum = 42161,
11    ArbitrumTestnet = 421611,
12    ArbitrumGoerli = 421613,
13    ArbitrumSepolia = 421614,
14    ArbitrumNova = 42170,
15}
16
17impl std::fmt::Display for Chain {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(
20            f,
21            "{}",
22            match self {
23                Chain::Dev => "Dev",
24                Chain::Arbitrum => "Arbitrum",
25                Chain::ArbitrumTestnet => "ArbitrumTestnet",
26                Chain::ArbitrumGoerli => "ArbitrumGoerli",
27                Chain::ArbitrumSepolia => "ArbitrumSepolia",
28                Chain::ArbitrumNova => "ArbitrumNova",
29            }
30        )
31    }
32}
33
34#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
35#[serde(rename_all = "PascalCase")]
36pub enum HyperliquidChain {
37    Mainnet,
38    Testnet,
39}
40
41impl std::fmt::Display for HyperliquidChain {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        write!(
44            f,
45            "{}",
46            match self {
47                HyperliquidChain::Mainnet => "Mainnet",
48                HyperliquidChain::Testnet => "Testnet",
49            }
50        )
51    }
52}
53
54pub enum API {
55    Info,
56    Exchange,
57}
58
59pub type Cloid = Uuid;
60
61#[derive(Debug, Serialize, Deserialize)]
62#[serde(untagged)]
63pub enum Oid {
64    Order(u64),
65    #[serde(serialize_with = "as_hex")]
66    Cloid(Cloid),
67}
68
69#[derive(Debug, Serialize, Deserialize)]
70#[serde(rename_all = "UPPERCASE")]
71pub enum Side {
72    B,
73    A,
74}
75pub mod agent {
76    pub mod l1 {
77        use ethers::{
78            contract::{Eip712, EthAbiType},
79            types::H256,
80        };
81
82        #[derive(Eip712, Clone, EthAbiType)]
83        #[eip712(
84            name = "Exchange",
85            version = "1",
86            chain_id = 1337,
87            verifying_contract = "0x0000000000000000000000000000000000000000"
88        )]
89        pub struct Agent {
90            pub source: String,
91            pub connection_id: H256,
92        }
93    }
94}
95
96pub mod info {
97    pub mod request {
98        use ethers::types::Address;
99        use serde::{Deserialize, Serialize};
100
101        use crate::types::Oid;
102
103        #[derive(Debug, Serialize, Deserialize)]
104        #[serde(rename_all = "camelCase")]
105        pub struct CandleSnapshotRequest {
106            pub coin: String,
107            pub interval: String,
108            pub start_time: u64,
109            pub end_time: u64,
110        }
111
112        #[derive(Debug, Serialize, Deserialize)]
113        #[serde(rename_all = "camelCase", tag = "type")]
114        pub enum Request {
115            Meta,
116            AllMids,
117            MetaAndAssetCtxs,
118            ClearinghouseState {
119                user: Address,
120            },
121            BatchClearinghouseStates {
122                users: Vec<Address>,
123            },
124            OpenOrders {
125                user: Address,
126            },
127
128            FrontendOpenOrders {
129                user: Address,
130            },
131            UserFills {
132                user: Address,
133            },
134            #[serde(rename_all = "camelCase")]
135            UserFillsByTime {
136                user: Address,
137                start_time: u64,
138                #[serde(skip_serializing_if = "Option::is_none")]
139                end_time: Option<u64>,
140            },
141            #[serde(rename_all = "camelCase")]
142            UserFunding {
143                user: Address,
144                start_time: u64,
145                end_time: Option<u64>,
146            },
147            #[serde(rename_all = "camelCase")]
148            FundingHistory {
149                coin: String,
150                start_time: u64,
151                end_time: Option<u64>,
152            },
153            L2Book {
154                coin: String,
155            },
156            RecentTrades {
157                coin: String,
158            },
159            CandleSnapshot {
160                req: CandleSnapshotRequest,
161            },
162            OrderStatus {
163                user: Address,
164                oid: Oid,
165            },
166            SubAccounts {
167                user: Address,
168            },
169
170            SpotMeta,
171
172            SpotMetaAndAssetCtxs,
173
174            SpotClearinghouseState {
175                user: Address,
176            },
177        }
178    }
179
180    pub mod response {
181        use ethers::types::Address;
182        use serde::{Deserialize, Serialize};
183
184        use crate::types::Side;
185
186        #[derive(Debug, Serialize, Deserialize)]
187        #[serde(rename_all = "camelCase")]
188        pub struct Asset {
189            pub name: String,
190            pub sz_decimals: u64,
191            pub max_leverage: u64,
192            pub only_isolated: bool,
193        }
194
195        #[derive(Debug, Serialize, Deserialize)]
196        #[serde(rename_all = "camelCase")]
197        pub struct Universe {
198            pub universe: Vec<Asset>,
199        }
200
201        #[derive(Debug, Serialize, Deserialize)]
202        #[serde(untagged)]
203        pub enum ImpactPx {
204            String(String),
205            StringArray(Vec<String>),
206        }
207
208        #[derive(Debug, Serialize, Deserialize)]
209        #[serde(rename_all = "camelCase")]
210        pub struct Ctx {
211            pub funding: String,
212            pub open_interest: String,
213            pub prev_day_px: String,
214            pub day_ntl_vlm: String,
215            pub premium: Option<String>,
216            pub oracle_px: String,
217            pub mark_px: String,
218            pub mid_px: Option<String>,
219            pub impact_pxs: Option<ImpactPx>,
220        }
221
222        #[derive(Debug, Serialize, Deserialize)]
223        #[serde(untagged)]
224        pub enum AssetContext {
225            Meta(Universe),
226            Ctx(Vec<Ctx>),
227        }
228
229        #[derive(Debug, Serialize, Deserialize)]
230        #[serde(rename_all = "camelCase")]
231        pub struct CumFunding {
232            pub all_time: String,
233            pub since_change: String,
234            pub since_open: String,
235        }
236
237        #[derive(Debug, Serialize, Deserialize)]
238        pub struct Leverage {
239            #[serde(rename = "type")]
240            pub type_: String,
241            pub value: u32,
242        }
243
244        #[derive(Debug, Serialize, Deserialize)]
245        #[serde(rename_all = "camelCase")]
246
247        pub struct Position {
248            pub coin: String,
249            pub cum_funding: CumFunding,
250            pub entry_px: Option<String>,
251            pub leverage: Leverage,
252            pub liquidation_px: Option<String>,
253            pub margin_used: String,
254            pub max_leverage: u32,
255            pub position_value: String,
256            pub return_on_equity: String,
257            pub szi: String,
258            pub unrealized_pnl: String,
259        }
260
261        #[derive(Debug, Serialize, Deserialize)]
262        #[serde(rename_all = "camelCase")]
263        pub struct AssetPosition {
264            pub position: Position,
265            #[serde(rename = "type")]
266            pub type_: String,
267        }
268
269        #[derive(Debug, Serialize, Deserialize)]
270        #[serde(rename_all = "camelCase")]
271        pub struct MarginSummary {
272            pub account_value: String,
273            pub total_margin_used: String,
274            pub total_ntl_pos: String,
275            pub total_raw_usd: String,
276        }
277
278        #[derive(Debug, Serialize, Deserialize)]
279        #[serde(rename_all = "camelCase")]
280        pub struct UserState {
281            pub asset_positions: Vec<AssetPosition>,
282            pub margin_summary: MarginSummary,
283            pub cross_margin_summary: MarginSummary,
284            pub withdrawable: String,
285            pub time: u64,
286            pub cross_maintenance_margin_used: String,
287        }
288
289        #[derive(Debug, Serialize, Deserialize)]
290        #[serde(rename_all = "camelCase")]
291        pub struct OpenOrder {
292            pub coin: String,
293            pub limit_px: String,
294            pub oid: u64,
295            pub side: Side,
296            pub sz: String,
297            pub timestamp: u64,
298        }
299
300        #[derive(Debug, Serialize, Deserialize)]
301        #[serde(rename_all = "camelCase")]
302        pub struct FrontendOpenOrders {
303            pub coin: String,
304            pub is_position_tpsl: bool,
305            pub is_trigger: bool,
306            pub limit_px: String,
307            pub oid: u64,
308            pub order_type: String,
309            pub orig_sz: String,
310            pub reduce_only: bool,
311            pub side: Side,
312            pub sz: String,
313            pub timestamp: u64,
314            pub trigger_condition: String,
315            pub trigger_px: String,
316        }
317
318        #[derive(Debug, Serialize, Deserialize)]
319        #[serde(rename_all = "camelCase")]
320        pub struct UserFill {
321            pub coin: String,
322            pub px: String,
323            pub sz: String,
324            pub side: Side,
325            pub time: u64,
326            pub start_position: String,
327            pub dir: String,
328            pub closed_pnl: String,
329            pub hash: String,
330            pub oid: u64,
331            pub crossed: bool,
332            pub fee: String,
333        }
334
335        #[derive(Debug, Serialize, Deserialize)]
336        #[serde(rename_all = "camelCase")]
337        pub struct Delta {
338            pub coin: String,
339            pub funding_rate: String,
340            pub szi: String,
341            #[serde(rename = "type")]
342            pub type_: String,
343            pub usdc: String,
344        }
345
346        #[derive(Debug, Serialize, Deserialize)]
347        #[serde(rename_all = "camelCase")]
348        pub struct UserFunding {
349            pub delta: Delta,
350            pub hash: String,
351            pub time: u64,
352        }
353
354        #[derive(Debug, Serialize, Deserialize)]
355        #[serde(rename_all = "camelCase")]
356        pub struct FundingHistory {
357            pub coin: String,
358            pub funding_rate: String,
359            pub premium: String,
360            pub time: u64,
361        }
362
363        #[derive(Debug, Serialize, Deserialize)]
364        #[serde(rename_all = "camelCase")]
365        pub struct Level {
366            pub px: String,
367            pub sz: String,
368            pub n: u64,
369        }
370
371        #[derive(Debug, Serialize, Deserialize)]
372        pub struct L2Book {
373            pub coin: String,
374            pub levels: Vec<Vec<Level>>,
375            pub time: u64,
376        }
377
378        #[derive(Debug, Serialize, Deserialize)]
379        #[serde(rename_all = "camelCase")]
380        pub struct RecentTrades {
381            pub coin: String,
382            pub side: Side,
383            pub px: String,
384            pub sz: String,
385            pub hash: String,
386            pub time: u64,
387        }
388
389        #[derive(Debug, Serialize, Deserialize)]
390        #[serde(rename_all = "camelCase")]
391        pub struct CandleSnapshot {
392            #[serde(rename = "T")]
393            pub t_: u64,
394            pub c: String,
395            pub h: String,
396            pub i: String,
397            pub l: String,
398            pub n: u64,
399            pub o: String,
400            pub s: String,
401            pub t: u64,
402            pub v: String,
403        }
404
405        #[derive(Debug, Serialize, Deserialize)]
406        #[serde(rename_all = "camelCase")]
407        pub struct OrderInfo {
408            pub children: Vec<Option<serde_json::Value>>,
409            pub cloid: Option<String>,
410            pub coin: String,
411            pub is_position_tpsl: bool,
412            pub is_trigger: bool,
413            pub limit_px: String,
414            pub oid: i64,
415            pub order_type: String,
416            pub orig_sz: String,
417            pub reduce_only: bool,
418            pub side: String,
419            pub sz: String,
420            pub tif: Option<String>,
421            pub timestamp: i64,
422            pub trigger_condition: String,
423            pub trigger_px: String,
424        }
425
426        #[derive(Debug, Serialize, Deserialize)]
427        #[serde(rename_all = "camelCase")]
428        pub struct Order {
429            pub order: OrderInfo,
430            pub status: String,
431            pub status_timestamp: i64,
432        }
433
434        #[derive(Debug, Serialize, Deserialize)]
435        #[serde(rename_all = "camelCase")]
436        pub struct OrderStatus {
437            pub order: Option<Order>,
438            pub status: String,
439        }
440
441        #[derive(Debug, Serialize, Deserialize)]
442        #[serde(rename_all = "camelCase")]
443        pub struct SubAccount {
444            pub clearinghouse_state: UserState,
445            pub master: Address,
446            pub name: String,
447            pub sub_account_user: Address,
448        }
449
450        #[derive(Debug, Serialize, Deserialize)]
451        #[serde(rename_all = "camelCase")]
452        pub struct SpotAsset {
453            pub index: u64,
454            pub is_canonical: bool,
455            pub name: String,
456            pub sz_decimals: u64,
457            pub token_id: String,
458            pub wei_decimals: u64,
459        }
460
461        #[derive(Debug, Serialize, Deserialize)]
462        #[serde(rename_all = "camelCase")]
463        pub struct SpotUniverse {
464            pub index: u64,
465            pub is_canonical: bool,
466            pub name: String,
467            pub tokens: Vec<u64>,
468        }
469
470        #[derive(Debug, Serialize, Deserialize)]
471        #[serde(rename_all = "camelCase")]
472        pub struct SpotMeta {
473            pub tokens: Vec<SpotAsset>,
474            pub universe: Vec<SpotUniverse>,
475        }
476
477        #[derive(Debug, Serialize, Deserialize)]
478        #[serde(rename_all = "camelCase")]
479        pub struct SpotCtx {
480            pub circulating_supply: String,
481            pub coin: String,
482            pub day_ntl_vlm: String,
483            pub mark_px: String,
484            pub mid_px: Option<String>,
485            pub prev_day_px: String,
486        }
487
488        #[derive(Debug, Serialize, Deserialize)]
489        #[serde(untagged)]
490        pub enum SpotMetaAndAssetCtxs {
491            Meta(SpotMeta),
492            Ctx(Vec<SpotCtx>),
493        }
494
495        #[derive(Debug, Serialize, Deserialize)]
496        pub struct Balance {
497            pub coin: String,
498            pub hold: String,
499            pub total: String,
500        }
501
502        #[derive(Debug, Serialize, Deserialize)]
503        #[serde(rename_all = "camelCase")]
504        pub struct UserSpotState {
505            pub balances: Vec<Balance>,
506        }
507    }
508}
509
510pub mod exchange {
511    pub mod request {
512
513        use ethers::{
514            abi::{encode, ParamType, Token, Tokenizable},
515            types::{
516                transaction::eip712::{
517                    encode_eip712_type, make_type_hash, EIP712Domain, Eip712, Eip712Error,
518                },
519                Address, Signature, H256, U256,
520            },
521            utils::keccak256,
522        };
523        use serde::{Deserialize, Serialize};
524
525        use crate::{
526            types::{Cloid, HyperliquidChain},
527            utils::{as_hex, as_hex_option},
528            Error, Result,
529        };
530
531        #[derive(Debug, Serialize, Deserialize)]
532        #[serde(rename_all = "PascalCase")]
533        pub enum Tif {
534            Gtc,
535            Ioc,
536            Alo,
537            FrontendMarket,
538        }
539
540        #[derive(Debug, Serialize, Deserialize)]
541        #[serde(rename_all = "camelCase")]
542        pub struct Limit {
543            pub tif: Tif,
544        }
545
546        #[derive(Debug, Serialize, Deserialize)]
547        #[serde(rename_all = "lowercase")]
548        pub enum TpSl {
549            Tp,
550            Sl,
551        }
552
553        #[derive(Debug, Serialize, Deserialize)]
554        #[serde(rename_all = "camelCase")]
555        pub struct Trigger {
556            pub is_market: bool,
557            pub trigger_px: String,
558            pub tpsl: TpSl,
559        }
560
561        #[derive(Debug, Serialize, Deserialize)]
562        #[serde(rename_all = "camelCase")]
563        pub enum OrderType {
564            Limit(Limit),
565            Trigger(Trigger),
566        }
567
568        #[derive(Debug, Serialize, Deserialize)]
569        #[serde(rename_all = "camelCase")]
570        pub struct OrderRequest {
571            #[serde(rename = "a", alias = "asset")]
572            pub asset: u32,
573            #[serde(rename = "b", alias = "isBuy")]
574            pub is_buy: bool,
575            #[serde(rename = "p", alias = "limitPx")]
576            pub limit_px: String,
577            #[serde(rename = "s", alias = "sz")]
578            pub sz: String,
579            #[serde(rename = "r", alias = "reduceOnly", default)]
580            pub reduce_only: bool,
581            #[serde(rename = "t", alias = "orderType")]
582            pub order_type: OrderType,
583            #[serde(
584                rename = "c",
585                alias = "cloid",
586                serialize_with = "as_hex_option",
587                skip_serializing_if = "Option::is_none"
588            )]
589            pub cloid: Option<Cloid>,
590        }
591
592        #[derive(Debug, Serialize, Deserialize)]
593        #[serde(rename_all = "camelCase")]
594        pub enum Grouping {
595            Na,
596            NormalTpsl,
597        }
598
599        #[derive(Debug, Serialize, Deserialize)]
600        #[serde(rename_all = "camelCase")]
601        pub struct CancelRequest {
602            #[serde(rename = "a", alias = "asset")]
603            pub asset: u32,
604            #[serde(rename = "o", alias = "oid")]
605            pub oid: u64,
606        }
607
608        #[derive(Debug, Serialize, Deserialize)]
609        #[serde(rename_all = "camelCase")]
610        pub struct CancelByCloidRequest {
611            pub asset: u32,
612            #[serde(serialize_with = "as_hex")]
613            pub cloid: Cloid,
614        }
615
616        #[derive(Debug, Serialize, Deserialize)]
617        #[serde(rename_all = "camelCase")]
618        pub struct ModifyRequest {
619            pub oid: u64,
620            pub order: OrderRequest,
621        }
622
623        #[derive(Debug, Serialize, Deserialize)]
624        #[serde(rename_all = "camelCase")]
625        pub struct TwapRequest {
626            #[serde(rename = "a", alias = "asset")]
627            pub asset: u32,
628            #[serde(rename = "b", alias = "isBuy")]
629            pub is_buy: bool,
630            #[serde(rename = "s", alias = "sz")]
631            pub sz: String,
632            #[serde(rename = "r", alias = "reduceOnly", default)]
633            pub reduce_only: bool,
634            /// Running Time (5m - 24h)
635            #[serde(rename = "m", alias = "duration")]
636            pub duration: u64,
637            /// if set to true, the size of each sub-trade will be automatically adjusted
638            /// within a certain range, typically upto to 20% higher or lower than the original trade size
639            #[serde(rename = "t", alias = "randomize")]
640            pub randomize: bool,
641        }
642
643        #[derive(Debug, Serialize, Deserialize)]
644        #[serde(rename_all = "camelCase")]
645        pub struct Withdraw3 {
646            pub signature_chain_id: U256,
647            pub hyperliquid_chain: HyperliquidChain,
648            pub destination: String,
649            pub amount: String,
650            pub time: u64,
651        }
652
653        impl Eip712 for Withdraw3 {
654            type Error = Eip712Error;
655
656            fn domain(&self) -> std::result::Result<EIP712Domain, Self::Error> {
657                Ok(EIP712Domain {
658                    name: Some("HyperliquidSignTransaction".into()),
659                    version: Some("1".into()),
660                    chain_id: Some(self.signature_chain_id),
661                    verifying_contract: Some(Address::zero()),
662                    salt: None,
663                })
664            }
665
666            fn type_hash() -> std::result::Result<[u8; 32], Self::Error> {
667                Ok(make_type_hash(
668                    "HyperliquidTransaction:Withdraw".into(),
669                    &[
670                        ("hyperliquidChain".to_string(), ParamType::String),
671                        ("destination".to_string(), ParamType::String),
672                        ("amount".to_string(), ParamType::String),
673                        ("time".to_string(), ParamType::Uint(64)),
674                    ],
675                ))
676            }
677
678            fn struct_hash(&self) -> std::result::Result<[u8; 32], Self::Error> {
679                Ok(keccak256(encode(&[
680                    Token::Uint(Self::type_hash()?.into()),
681                    encode_eip712_type(self.hyperliquid_chain.to_string().into_token()),
682                    encode_eip712_type(self.destination.clone().into_token()),
683                    encode_eip712_type(self.amount.clone().into_token()),
684                    encode_eip712_type(self.time.into_token()),
685                ])))
686            }
687        }
688
689        #[derive(Debug, Serialize, Deserialize)]
690        #[serde(rename_all = "camelCase")]
691        pub struct Agent {
692            pub source: String,
693            pub connection_id: H256,
694        }
695
696        #[derive(Debug, Serialize, Deserialize)]
697        #[serde(rename_all = "camelCase")]
698        pub struct UsdSend {
699            pub signature_chain_id: U256,
700            pub hyperliquid_chain: HyperliquidChain,
701            pub destination: String,
702            pub amount: String,
703            pub time: u64,
704        }
705
706        impl Eip712 for UsdSend {
707            type Error = Eip712Error;
708
709            fn domain(&self) -> std::result::Result<EIP712Domain, Self::Error> {
710                Ok(EIP712Domain {
711                    name: Some("HyperliquidSignTransaction".into()),
712                    version: Some("1".into()),
713                    chain_id: Some(self.signature_chain_id),
714                    verifying_contract: Some(Address::zero()),
715                    salt: None,
716                })
717            }
718
719            fn type_hash() -> std::result::Result<[u8; 32], Self::Error> {
720                Ok(make_type_hash(
721                    "HyperliquidTransaction:UsdSend".into(),
722                    &[
723                        ("hyperliquidChain".to_string(), ParamType::String),
724                        ("destination".to_string(), ParamType::String),
725                        ("amount".to_string(), ParamType::String),
726                        ("time".to_string(), ParamType::Uint(64)),
727                    ],
728                ))
729            }
730
731            fn struct_hash(&self) -> std::result::Result<[u8; 32], Self::Error> {
732                Ok(keccak256(encode(&[
733                    Token::Uint(Self::type_hash()?.into()),
734                    encode_eip712_type(self.hyperliquid_chain.to_string().into_token()),
735                    encode_eip712_type(self.destination.clone().into_token()),
736                    encode_eip712_type(self.amount.clone().into_token()),
737                    encode_eip712_type(self.time.into_token()),
738                ])))
739            }
740        }
741
742        #[derive(Debug, Serialize, Deserialize)]
743        #[serde(rename_all = "camelCase")]
744        pub struct ApproveAgent {
745            pub signature_chain_id: U256,
746            pub hyperliquid_chain: HyperliquidChain,
747            pub agent_address: Address,
748            #[serde(skip_serializing_if = "Option::is_none")]
749            pub agent_name: Option<String>,
750            pub nonce: u64,
751        }
752
753        impl Eip712 for ApproveAgent {
754            type Error = Eip712Error;
755
756            fn domain(&self) -> std::result::Result<EIP712Domain, Self::Error> {
757                Ok(EIP712Domain {
758                    name: Some("HyperliquidSignTransaction".into()),
759                    version: Some("1".into()),
760                    chain_id: Some(self.signature_chain_id),
761                    verifying_contract: Some(Address::zero()),
762                    salt: None,
763                })
764            }
765
766            fn type_hash() -> std::result::Result<[u8; 32], Self::Error> {
767                Ok(make_type_hash(
768                    "HyperliquidTransaction:ApproveAgent".into(),
769                    &[
770                        ("hyperliquidChain".to_string(), ParamType::String),
771                        ("agentAddress".to_string(), ParamType::Address),
772                        ("agentName".to_string(), ParamType::String),
773                        ("nonce".to_string(), ParamType::Uint(64)),
774                    ],
775                ))
776            }
777
778            fn struct_hash(&self) -> std::result::Result<[u8; 32], Self::Error> {
779                Ok(keccak256(encode(&[
780                    Token::Uint(Self::type_hash()?.into()),
781                    encode_eip712_type(self.hyperliquid_chain.to_string().into_token()),
782                    encode_eip712_type(self.agent_address.into_token()),
783                    encode_eip712_type(self.agent_name.clone().unwrap_or_default().into_token()),
784                    encode_eip712_type(self.nonce.into_token()),
785                ])))
786            }
787        }
788
789        #[derive(Debug, Serialize, Deserialize)]
790        #[serde(rename_all = "camelCase", tag = "type")]
791        pub enum Action {
792            Order {
793                orders: Vec<OrderRequest>,
794                grouping: Grouping,
795            },
796            Cancel {
797                cancels: Vec<CancelRequest>,
798            },
799            CancelByCloid {
800                cancels: Vec<CancelByCloidRequest>,
801            },
802
803            Modify(ModifyRequest),
804
805            BatchModify {
806                modifies: Vec<ModifyRequest>,
807            },
808            TwapOrder {
809                twap: TwapRequest,
810            },
811            UsdSend(UsdSend),
812
813            Withdraw3(Withdraw3),
814            #[serde(rename_all = "camelCase")]
815            UpdateLeverage {
816                asset: u32,
817                is_cross: bool,
818                leverage: u32,
819            },
820            #[serde(rename_all = "camelCase")]
821            UpdateIsolatedMargin {
822                asset: u32,
823                is_buy: bool,
824                ntli: i64,
825            },
826            ApproveAgent(ApproveAgent),
827            CreateSubAccount {
828                name: String,
829            },
830            #[serde(rename_all = "camelCase")]
831            SubAccountModify {
832                sub_account_user: Address,
833                name: String,
834            },
835            #[serde(rename_all = "camelCase")]
836            SubAccountTransfer {
837                sub_account_user: Address,
838                is_deposit: bool,
839                usd: u64,
840            },
841            SetReferrer {
842                code: String,
843            },
844            ScheduleCancel {
845                time: u64,
846            },
847        }
848
849        impl Action {
850            /// create connection id for agent
851            pub fn connection_id(
852                &self,
853                vault_address: Option<Address>,
854                nonce: u64,
855            ) -> Result<H256> {
856                let mut encoded = rmp_serde::to_vec_named(self)
857                    .map_err(|e| Error::RmpSerdeError(e.to_string()))?;
858
859                encoded.extend((nonce).to_be_bytes());
860
861                if let Some(address) = vault_address {
862                    encoded.push(1);
863                    encoded.extend(address.to_fixed_bytes());
864                } else {
865                    encoded.push(0)
866                }
867
868                Ok(keccak256(encoded).into())
869            }
870        }
871
872        #[derive(Debug, Serialize, Deserialize)]
873        #[serde(rename_all = "camelCase")]
874        pub struct Request {
875            pub action: Action,
876            pub nonce: u64,
877            pub signature: Signature,
878            #[serde(skip_serializing_if = "Option::is_none")]
879            pub vault_address: Option<Address>,
880        }
881    }
882
883    pub mod response {
884        use ethers::types::Address;
885        use serde::{Deserialize, Serialize};
886
887        #[derive(Debug, Serialize, Deserialize)]
888        pub struct Resting {
889            pub oid: u64,
890        }
891
892        #[derive(Debug, Serialize, Deserialize)]
893        #[serde(rename_all = "camelCase")]
894        pub struct Filled {
895            pub oid: u64,
896            pub total_sz: String,
897            pub avg_px: String,
898        }
899
900        #[derive(Debug, Serialize, Deserialize)]
901        #[serde(rename_all = "camelCase")]
902        pub struct TwapId {
903            pub twap_id: u64,
904        }
905
906        #[derive(Debug, Serialize, Deserialize)]
907        #[serde(rename_all = "camelCase")]
908        pub enum Status {
909            Resting(Resting),
910            Filled(Filled),
911            Error(String),
912            Success,
913            WaitingForFill,
914            WaitingForTrigger,
915            Running(TwapId),
916        }
917
918        #[derive(Debug, Serialize, Deserialize)]
919        #[serde(rename_all = "camelCase")]
920        pub enum StatusType {
921            Statuses(Vec<Status>),
922            Status(Status),
923            #[serde(untagged)]
924            Address(Address),
925        }
926
927        #[derive(Debug, Serialize, Deserialize)]
928        pub struct Data {
929            #[serde(rename = "type")]
930            pub type_: String,
931            pub data: Option<StatusType>,
932        }
933
934        #[derive(Debug, Serialize, Deserialize)]
935        #[serde(rename_all = "camelCase", tag = "status", content = "response")]
936        pub enum Response {
937            Ok(Data),
938            Err(String),
939        }
940    }
941}
942
943pub mod websocket {
944    pub mod request {
945        use ethers::types::Address;
946        use serde::{Deserialize, Serialize};
947
948        #[derive(Debug, Serialize, Deserialize, Clone)]
949        #[serde(rename_all = "camelCase", tag = "type")]
950        pub enum Subscription {
951            AllMids,
952            Notification { user: Address },
953            OrderUpdates { user: Address },
954            User { user: Address },
955            WebData { user: Address },
956            L2Book { coin: String },
957            Trades { coin: String },
958            Candle { coin: String, interval: String },
959        }
960
961        #[derive(Clone)]
962        pub struct Channel {
963            pub id: u64,
964            pub sub: Subscription,
965        }
966
967        #[derive(Debug, Serialize, Deserialize)]
968        #[serde(rename_all = "lowercase")]
969        pub enum Method {
970            Subscribe,
971            Unsubscribe,
972        }
973
974        #[derive(Debug, Serialize, Deserialize)]
975        #[serde(rename_all = "camelCase")]
976        pub struct Request {
977            pub method: Method,
978            pub subscription: Subscription,
979        }
980    }
981
982    pub mod response {
983        use std::collections::HashMap;
984
985        use ethers::types::{Address, TxHash};
986        use serde::{Deserialize, Serialize};
987        use serde_json::Value;
988
989        use crate::types::{
990            info::response::{CandleSnapshot, Ctx, Universe, UserFill, UserState},
991            Side,
992        };
993
994        #[derive(Debug, Serialize, Deserialize)]
995        pub struct AllMids {
996            pub mids: HashMap<String, String>,
997        }
998
999        #[derive(Debug, Serialize, Deserialize)]
1000        pub struct Notification {
1001            pub notification: String,
1002        }
1003
1004        #[derive(Debug, Serialize, Deserialize)]
1005        pub struct LedgerUpdate {
1006            pub hash: TxHash,
1007            pub delta: Value,
1008            pub time: u64,
1009        }
1010
1011        #[derive(Debug, Serialize, Deserialize)]
1012        #[serde(rename_all = "camelCase")]
1013        pub struct WebData {
1014            pub user_state: UserState,
1015            pub lending_vaults: Option<Vec<Value>>,
1016            pub total_vault_equity: String,
1017            pub open_orders: Vec<Value>,
1018            pub fills: Vec<Value>,
1019            pub whitelisted: bool,
1020            pub ledger_updates: Vec<LedgerUpdate>,
1021            pub agent_address: Address,
1022            pub pending_withdraws: Option<Vec<Value>>,
1023            pub cum_ledger: String,
1024            pub meta: Universe,
1025            pub asset_contexts: Option<Vec<Ctx>>,
1026            pub order_history: Vec<Value>,
1027            pub server_time: u64,
1028            pub is_vault: bool,
1029            pub user: Address,
1030        }
1031
1032        #[derive(Debug, Serialize, Deserialize)]
1033        pub struct WsTrade {
1034            pub coin: String,
1035            pub side: String,
1036            pub px: String,
1037            pub sz: String,
1038            pub hash: TxHash,
1039            pub time: u64,
1040        }
1041
1042        #[derive(Debug, Serialize, Deserialize)]
1043        pub struct WsLevel {
1044            pub px: String,
1045            pub sz: String,
1046            pub n: u64,
1047        }
1048
1049        #[derive(Debug, Serialize, Deserialize)]
1050        pub struct WsBook {
1051            pub coin: String,
1052            pub levels: Vec<Vec<WsLevel>>,
1053            pub time: u64,
1054        }
1055
1056        #[derive(Debug, Serialize, Deserialize)]
1057        #[serde(rename_all = "camelCase")]
1058        pub struct WsBasicOrder {
1059            pub coin: String,
1060            pub side: Side,
1061            pub limit_px: String,
1062            pub sz: String,
1063            pub oid: u64,
1064            pub timestamp: u64,
1065            pub orig_sz: String,
1066            #[serde(default)]
1067            pub reduce_only: bool,
1068        }
1069
1070        #[derive(Debug, Serialize, Deserialize)]
1071        #[serde(rename_all = "camelCase")]
1072        pub struct WsOrder {
1073            pub order: WsBasicOrder,
1074            pub status: String,
1075            pub status_timestamp: u64,
1076        }
1077
1078        #[derive(Debug, Serialize, Deserialize)]
1079        #[serde(rename_all = "camelCase")]
1080        pub struct WsUserFunding {
1081            pub time: u64,
1082            pub coin: String,
1083            pub usdc: String,
1084            pub szi: String,
1085            pub funding_rate: String,
1086        }
1087
1088        #[derive(Debug, Serialize, Deserialize)]
1089        #[serde(rename_all = "snake_case")]
1090        pub struct WsLiquidation {
1091            pub liq: u64,
1092            pub liquidator: String,
1093            pub liquidated_user: String,
1094            pub liquidated_ntl_pos: String,
1095            pub liquidated_account_value: String,
1096        }
1097
1098        #[derive(Debug, Serialize, Deserialize)]
1099        #[serde(rename_all = "camelCase")]
1100        pub struct WsNonUserCancel {
1101            pub oid: u64,
1102            pub coin: String,
1103        }
1104
1105        #[derive(Debug, Serialize, Deserialize)]
1106        #[serde(rename_all = "camelCase", untagged)]
1107        pub enum WsUserEvent {
1108            WsFill(Vec<UserFill>),
1109            WsUserFunding(WsUserFunding),
1110            WsLiquidation(WsLiquidation),
1111            WsNonUserCancel(Vec<WsNonUserCancel>),
1112        }
1113
1114        #[derive(Debug, Serialize, Deserialize)]
1115        pub struct Channel {
1116            pub method: String,
1117            pub subscription: Value,
1118        }
1119
1120        #[derive(Debug, Serialize, Deserialize)]
1121        #[serde(rename_all = "camelCase", tag = "channel", content = "data")]
1122        pub enum Response {
1123            AllMids(AllMids),
1124            Notification(Notification),
1125            WebData(WebData),
1126            Candle(CandleSnapshot),
1127            L2Book(WsBook),
1128            Trades(Vec<WsTrade>),
1129            OrderUpdates(Vec<WsOrder>),
1130            User(WsUserEvent),
1131            SubscriptionResponse(Channel),
1132        }
1133    }
1134}