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 #[serde(rename = "m", alias = "duration")]
636 pub duration: u64,
637 #[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 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}