Thanks to visit codestin.com
Credit goes to docs.rs

hyperliquid_rust_sdk/exchange/
actions.rs

1use crate::exchange::{cancel::CancelRequest, modify::ModifyRequest, order::OrderRequest};
2pub(crate) use ethers::{
3    abi::{encode, ParamType, Tokenizable},
4    types::{
5        transaction::{
6            eip712,
7            eip712::{encode_eip712_type, EIP712Domain, Eip712, Eip712Error},
8        },
9        H160, U256,
10    },
11    utils::keccak256,
12};
13use serde::{Deserialize, Serialize};
14
15use super::{cancel::CancelRequestCloid, BuilderInfo};
16
17pub(crate) const HYPERLIQUID_EIP_PREFIX: &str = "HyperliquidTransaction:";
18
19fn eip_712_domain(chain_id: U256) -> EIP712Domain {
20    EIP712Domain {
21        name: Some("HyperliquidSignTransaction".to_string()),
22        version: Some("1".to_string()),
23        chain_id: Some(chain_id),
24        verifying_contract: Some(
25            "0x0000000000000000000000000000000000000000"
26                .parse()
27                .unwrap(),
28        ),
29        salt: None,
30    }
31}
32
33#[derive(Serialize, Deserialize, Debug, Clone)]
34#[serde(rename_all = "camelCase")]
35pub struct UsdSend {
36    pub signature_chain_id: U256,
37    pub hyperliquid_chain: String,
38    pub destination: String,
39    pub amount: String,
40    pub time: u64,
41}
42
43impl Eip712 for UsdSend {
44    type Error = Eip712Error;
45
46    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
47        Ok(eip_712_domain(self.signature_chain_id))
48    }
49
50    fn type_hash() -> Result<[u8; 32], Self::Error> {
51        Ok(eip712::make_type_hash(
52            format!("{HYPERLIQUID_EIP_PREFIX}UsdSend"),
53            &[
54                ("hyperliquidChain".to_string(), ParamType::String),
55                ("destination".to_string(), ParamType::String),
56                ("amount".to_string(), ParamType::String),
57                ("time".to_string(), ParamType::Uint(64)),
58            ],
59        ))
60    }
61
62    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
63        let Self {
64            signature_chain_id: _,
65            hyperliquid_chain,
66            destination,
67            amount,
68            time,
69        } = self;
70        let items = vec![
71            ethers::abi::Token::Uint(Self::type_hash()?.into()),
72            encode_eip712_type(hyperliquid_chain.clone().into_token()),
73            encode_eip712_type(destination.clone().into_token()),
74            encode_eip712_type(amount.clone().into_token()),
75            encode_eip712_type(time.into_token()),
76        ];
77        Ok(keccak256(encode(&items)))
78    }
79}
80
81#[derive(Serialize, Deserialize, Debug, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct UpdateLeverage {
84    pub asset: u32,
85    pub is_cross: bool,
86    pub leverage: u32,
87}
88
89#[derive(Serialize, Deserialize, Debug, Clone)]
90#[serde(rename_all = "camelCase")]
91pub struct UpdateIsolatedMargin {
92    pub asset: u32,
93    pub is_buy: bool,
94    pub ntli: i64,
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone)]
98#[serde(rename_all = "camelCase")]
99pub struct BulkOrder {
100    pub orders: Vec<OrderRequest>,
101    pub grouping: String,
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub builder: Option<BuilderInfo>,
104}
105
106#[derive(Serialize, Deserialize, Debug, Clone)]
107#[serde(rename_all = "camelCase")]
108pub struct BulkCancel {
109    pub cancels: Vec<CancelRequest>,
110}
111
112#[derive(Serialize, Deserialize, Debug, Clone)]
113#[serde(rename_all = "camelCase")]
114pub struct BulkModify {
115    pub modifies: Vec<ModifyRequest>,
116}
117
118#[derive(Serialize, Deserialize, Debug, Clone)]
119#[serde(rename_all = "camelCase")]
120pub struct BulkCancelCloid {
121    pub cancels: Vec<CancelRequestCloid>,
122}
123
124#[derive(Serialize, Deserialize, Debug, Clone)]
125#[serde(rename_all = "camelCase")]
126pub struct ApproveAgent {
127    pub signature_chain_id: U256,
128    pub hyperliquid_chain: String,
129    pub agent_address: H160,
130    pub agent_name: Option<String>,
131    pub nonce: u64,
132}
133
134impl Eip712 for ApproveAgent {
135    type Error = Eip712Error;
136
137    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
138        Ok(eip_712_domain(self.signature_chain_id))
139    }
140
141    fn type_hash() -> Result<[u8; 32], Self::Error> {
142        Ok(eip712::make_type_hash(
143            format!("{HYPERLIQUID_EIP_PREFIX}ApproveAgent"),
144            &[
145                ("hyperliquidChain".to_string(), ParamType::String),
146                ("agentAddress".to_string(), ParamType::Address),
147                ("agentName".to_string(), ParamType::String),
148                ("nonce".to_string(), ParamType::Uint(64)),
149            ],
150        ))
151    }
152
153    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
154        let Self {
155            signature_chain_id: _,
156            hyperliquid_chain,
157            agent_address,
158            agent_name,
159            nonce,
160        } = self;
161        let items = vec![
162            ethers::abi::Token::Uint(Self::type_hash()?.into()),
163            encode_eip712_type(hyperliquid_chain.clone().into_token()),
164            encode_eip712_type(agent_address.into_token()),
165            encode_eip712_type(agent_name.clone().unwrap_or_default().into_token()),
166            encode_eip712_type(nonce.into_token()),
167        ];
168        Ok(keccak256(encode(&items)))
169    }
170}
171
172#[derive(Serialize, Deserialize, Debug, Clone)]
173#[serde(rename_all = "camelCase")]
174pub struct Withdraw3 {
175    pub hyperliquid_chain: String,
176    pub signature_chain_id: U256,
177    pub amount: String,
178    pub time: u64,
179    pub destination: String,
180}
181
182impl Eip712 for Withdraw3 {
183    type Error = Eip712Error;
184
185    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
186        Ok(eip_712_domain(self.signature_chain_id))
187    }
188
189    fn type_hash() -> Result<[u8; 32], Self::Error> {
190        Ok(eip712::make_type_hash(
191            format!("{HYPERLIQUID_EIP_PREFIX}Withdraw"),
192            &[
193                ("hyperliquidChain".to_string(), ParamType::String),
194                ("destination".to_string(), ParamType::String),
195                ("amount".to_string(), ParamType::String),
196                ("time".to_string(), ParamType::Uint(64)),
197            ],
198        ))
199    }
200
201    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
202        let Self {
203            signature_chain_id: _,
204            hyperliquid_chain,
205            amount,
206            time,
207            destination,
208        } = self;
209        let items = vec![
210            ethers::abi::Token::Uint(Self::type_hash()?.into()),
211            encode_eip712_type(hyperliquid_chain.clone().into_token()),
212            encode_eip712_type(destination.clone().into_token()),
213            encode_eip712_type(amount.clone().into_token()),
214            encode_eip712_type(time.into_token()),
215        ];
216        Ok(keccak256(encode(&items)))
217    }
218}
219
220#[derive(Serialize, Deserialize, Debug, Clone)]
221#[serde(rename_all = "camelCase")]
222pub struct SpotSend {
223    pub hyperliquid_chain: String,
224    pub signature_chain_id: U256,
225    pub destination: String,
226    pub token: String,
227    pub amount: String,
228    pub time: u64,
229}
230
231impl Eip712 for SpotSend {
232    type Error = Eip712Error;
233
234    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
235        Ok(eip_712_domain(self.signature_chain_id))
236    }
237
238    fn type_hash() -> Result<[u8; 32], Self::Error> {
239        Ok(eip712::make_type_hash(
240            format!("{HYPERLIQUID_EIP_PREFIX}SpotSend"),
241            &[
242                ("hyperliquidChain".to_string(), ParamType::String),
243                ("destination".to_string(), ParamType::String),
244                ("token".to_string(), ParamType::String),
245                ("amount".to_string(), ParamType::String),
246                ("time".to_string(), ParamType::Uint(64)),
247            ],
248        ))
249    }
250
251    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
252        let Self {
253            signature_chain_id: _,
254            hyperliquid_chain,
255            destination,
256            token,
257            amount,
258            time,
259        } = self;
260        let items = vec![
261            ethers::abi::Token::Uint(Self::type_hash()?.into()),
262            encode_eip712_type(hyperliquid_chain.clone().into_token()),
263            encode_eip712_type(destination.clone().into_token()),
264            encode_eip712_type(token.clone().into_token()),
265            encode_eip712_type(amount.clone().into_token()),
266            encode_eip712_type(time.into_token()),
267        ];
268        Ok(keccak256(encode(&items)))
269    }
270}
271
272#[derive(Serialize, Deserialize, Debug, Clone)]
273#[serde(rename_all = "camelCase")]
274pub struct SpotUser {
275    pub class_transfer: ClassTransfer,
276}
277
278#[derive(Serialize, Deserialize, Debug, Clone)]
279#[serde(rename_all = "camelCase")]
280pub struct ClassTransfer {
281    pub usdc: u64,
282    pub to_perp: bool,
283}
284
285#[derive(Serialize, Deserialize, Debug, Clone)]
286#[serde(rename_all = "camelCase")]
287pub struct VaultTransfer {
288    pub vault_address: H160,
289    pub is_deposit: bool,
290    pub usd: u64,
291}
292
293#[derive(Serialize, Deserialize, Debug, Clone)]
294#[serde(rename_all = "camelCase")]
295pub struct SetReferrer {
296    pub code: String,
297}
298
299#[derive(Serialize, Deserialize, Debug, Clone)]
300#[serde(rename_all = "camelCase")]
301pub struct ApproveBuilderFee {
302    pub max_fee_rate: String,
303    pub builder: String,
304    pub nonce: u64,
305    pub signature_chain_id: U256,
306    pub hyperliquid_chain: String,
307}