hyperliquid_rust_sdk_abrkn/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;
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}
103
104#[derive(Serialize, Deserialize, Debug, Clone)]
105#[serde(rename_all = "camelCase")]
106pub struct BulkCancel {
107    pub cancels: Vec<CancelRequest>,
108}
109
110#[derive(Serialize, Deserialize, Debug, Clone)]
111#[serde(rename_all = "camelCase")]
112pub struct BulkModify {
113    pub modifies: Vec<ModifyRequest>,
114}
115
116#[derive(Serialize, Deserialize, Debug, Clone)]
117#[serde(rename_all = "camelCase")]
118pub struct BulkCancelCloid {
119    pub cancels: Vec<CancelRequestCloid>,
120}
121
122#[derive(Serialize, Deserialize, Debug, Clone)]
123#[serde(rename_all = "camelCase")]
124pub struct ApproveAgent {
125    pub signature_chain_id: U256,
126    pub hyperliquid_chain: String,
127    pub agent_address: H160,
128    pub agent_name: Option<String>,
129    pub nonce: u64,
130}
131
132impl Eip712 for ApproveAgent {
133    type Error = Eip712Error;
134
135    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
136        Ok(eip_712_domain(self.signature_chain_id))
137    }
138
139    fn type_hash() -> Result<[u8; 32], Self::Error> {
140        Ok(eip712::make_type_hash(
141            format!("{HYPERLIQUID_EIP_PREFIX}ApproveAgent"),
142            &[
143                ("hyperliquidChain".to_string(), ParamType::String),
144                ("agentAddress".to_string(), ParamType::Address),
145                ("agentName".to_string(), ParamType::String),
146                ("nonce".to_string(), ParamType::Uint(64)),
147            ],
148        ))
149    }
150
151    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
152        let Self {
153            signature_chain_id: _,
154            hyperliquid_chain,
155            agent_address,
156            agent_name,
157            nonce,
158        } = self;
159        let items = vec![
160            ethers::abi::Token::Uint(Self::type_hash()?.into()),
161            encode_eip712_type(hyperliquid_chain.clone().into_token()),
162            encode_eip712_type(agent_address.into_token()),
163            encode_eip712_type(agent_name.clone().unwrap_or_default().into_token()),
164            encode_eip712_type(nonce.into_token()),
165        ];
166        Ok(keccak256(encode(&items)))
167    }
168}
169
170#[derive(Serialize, Deserialize, Debug, Clone)]
171#[serde(rename_all = "camelCase")]
172pub struct Withdraw3 {
173    pub hyperliquid_chain: String,
174    pub signature_chain_id: U256,
175    pub amount: String,
176    pub time: u64,
177    pub destination: String,
178}
179
180impl Eip712 for Withdraw3 {
181    type Error = Eip712Error;
182
183    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
184        Ok(eip_712_domain(self.signature_chain_id))
185    }
186
187    fn type_hash() -> Result<[u8; 32], Self::Error> {
188        Ok(eip712::make_type_hash(
189            format!("{HYPERLIQUID_EIP_PREFIX}Withdraw"),
190            &[
191                ("hyperliquidChain".to_string(), ParamType::String),
192                ("destination".to_string(), ParamType::String),
193                ("amount".to_string(), ParamType::String),
194                ("time".to_string(), ParamType::Uint(64)),
195            ],
196        ))
197    }
198
199    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
200        let Self {
201            signature_chain_id: _,
202            hyperliquid_chain,
203            amount,
204            time,
205            destination,
206        } = self;
207        let items = vec![
208            ethers::abi::Token::Uint(Self::type_hash()?.into()),
209            encode_eip712_type(hyperliquid_chain.clone().into_token()),
210            encode_eip712_type(destination.clone().into_token()),
211            encode_eip712_type(amount.clone().into_token()),
212            encode_eip712_type(time.into_token()),
213        ];
214        Ok(keccak256(encode(&items)))
215    }
216}
217
218#[derive(Serialize, Deserialize, Debug, Clone)]
219#[serde(rename_all = "camelCase")]
220pub struct SpotSend {
221    pub hyperliquid_chain: String,
222    pub signature_chain_id: U256,
223    pub destination: String,
224    pub token: String,
225    pub amount: String,
226    pub time: u64,
227}
228
229impl Eip712 for SpotSend {
230    type Error = Eip712Error;
231
232    fn domain(&self) -> Result<EIP712Domain, Self::Error> {
233        Ok(eip_712_domain(self.signature_chain_id))
234    }
235
236    fn type_hash() -> Result<[u8; 32], Self::Error> {
237        Ok(eip712::make_type_hash(
238            format!("{HYPERLIQUID_EIP_PREFIX}SpotSend"),
239            &[
240                ("hyperliquidChain".to_string(), ParamType::String),
241                ("destination".to_string(), ParamType::String),
242                ("token".to_string(), ParamType::String),
243                ("amount".to_string(), ParamType::String),
244                ("time".to_string(), ParamType::Uint(64)),
245            ],
246        ))
247    }
248
249    fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
250        let Self {
251            signature_chain_id: _,
252            hyperliquid_chain,
253            destination,
254            token,
255            amount,
256            time,
257        } = self;
258        let items = vec![
259            ethers::abi::Token::Uint(Self::type_hash()?.into()),
260            encode_eip712_type(hyperliquid_chain.clone().into_token()),
261            encode_eip712_type(destination.clone().into_token()),
262            encode_eip712_type(token.clone().into_token()),
263            encode_eip712_type(amount.clone().into_token()),
264            encode_eip712_type(time.into_token()),
265        ];
266        Ok(keccak256(encode(&items)))
267    }
268}
269
270#[derive(Serialize, Deserialize, Debug, Clone)]
271#[serde(rename_all = "camelCase")]
272pub struct SpotUser {
273    pub class_transfer: ClassTransfer,
274}
275
276#[derive(Serialize, Deserialize, Debug, Clone)]
277#[serde(rename_all = "camelCase")]
278pub struct ClassTransfer {
279    pub usdc: u64,
280    pub to_perp: bool,
281}
282
283#[derive(Serialize, Deserialize, Debug, Clone)]
284#[serde(rename_all = "camelCase")]
285pub struct VaultTransfer {
286    pub vault_address: H160,
287    pub is_deposit: bool,
288    pub usd: String,
289}
290
291#[derive(Serialize, Deserialize, Debug, Clone)]
292#[serde(rename_all = "camelCase")]
293pub struct SetReferrer {
294    pub code: String,
295}