Skip to content

Commit 5af799f

Browse files
committed
fix serialization format in UsdClassTransfer
1 parent aac7558 commit 5af799f

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

src/exchange/actions.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,30 @@ impl Eip712 for SpotSend {
186186

187187
#[derive(Serialize, Deserialize, Debug, Clone)]
188188
#[serde(rename_all = "camelCase")]
189-
pub struct SpotUser {
190-
pub class_transfer: ClassTransfer,
189+
pub struct UsdClassTransfer {
190+
#[serde(serialize_with = "serialize_hex")]
191+
pub signature_chain_id: u64,
192+
pub hyperliquid_chain: String,
193+
pub amount: String,
194+
pub to_perp: bool,
195+
pub nonce: u64,
191196
}
192197

193-
#[derive(Serialize, Deserialize, Debug, Clone)]
194-
#[serde(rename_all = "camelCase")]
195-
pub struct ClassTransfer {
196-
pub usdc: u64,
197-
pub to_perp: bool,
198+
impl Eip712 for UsdClassTransfer {
199+
fn domain(&self) -> Eip712Domain {
200+
eip_712_domain(self.signature_chain_id)
201+
}
202+
203+
fn struct_hash(&self) -> B256 {
204+
let items = (
205+
keccak256("HyperliquidTransaction:UsdClassTransfer(string hyperliquidChain,string amount,bool toPerp,uint64 nonce)"),
206+
keccak256(&self.hyperliquid_chain),
207+
keccak256(&self.amount),
208+
self.to_perp,
209+
&self.nonce,
210+
);
211+
keccak256(items.abi_encode())
212+
}
198213
}
199214

200215
#[derive(Serialize, Deserialize, Debug, Clone)]

src/exchange/exchange_client.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
actions::{
1414
ApproveAgent, ApproveBuilderFee, BulkCancel, BulkModify, BulkOrder, ClaimRewards,
1515
EvmUserModify, ScheduleCancel, SendAsset, SetReferrer, UpdateIsolatedMargin,
16-
UpdateLeverage, UsdSend,
16+
UpdateLeverage, UsdClassTransfer, UsdSend,
1717
},
1818
cancel::{CancelRequest, CancelRequestCloid, ClientCancelRequestCloid},
1919
modify::{ClientModifyRequest, ModifyRequest},
@@ -26,8 +26,7 @@ use crate::{
2626
prelude::*,
2727
req::HttpClient,
2828
signature::{sign_l1_action, sign_typed_data},
29-
BaseUrl, BulkCancelCloid, ClassTransfer, Error, ExchangeResponseStatus, SpotSend, SpotUser,
30-
VaultTransfer, Withdraw3,
29+
BaseUrl, BulkCancelCloid, Error, ExchangeResponseStatus, SpotSend, VaultTransfer, Withdraw3,
3130
};
3231

3332
#[derive(Debug)]
@@ -57,6 +56,8 @@ struct ExchangePayload {
5756
#[serde(serialize_with = "serialize_sig")]
5857
signature: Signature,
5958
nonce: u64,
59+
#[serde(skip_serializing_if = "Option::is_none")]
60+
// TODO: check if skip is needed
6061
vault_address: Option<Address>,
6162
}
6263

@@ -73,7 +74,6 @@ pub enum Actions {
7374
BatchModify(BulkModify),
7475
ApproveAgent(ApproveAgent),
7576
Withdraw3(Withdraw3),
76-
SpotUser(SpotUser),
7777
SendAsset(SendAsset),
7878
VaultTransfer(VaultTransfer),
7979
SpotSend(SpotSend),
@@ -82,6 +82,7 @@ pub enum Actions {
8282
EvmUserModify(EvmUserModify),
8383
ScheduleCancel(ScheduleCancel),
8484
ClaimRewards(ClaimRewards),
85+
UsdClassTransfer(UsdClassTransfer),
8586
}
8687

8788
impl Actions {
@@ -218,25 +219,30 @@ impl ExchangeClient {
218219

219220
pub async fn class_transfer(
220221
&self,
221-
usdc: f64,
222+
usd_amount: f64,
222223
to_perp: bool,
223224
wallet: Option<&PrivateKeySigner>,
224225
) -> Result<ExchangeResponseStatus> {
225-
// payload expects usdc without decimals
226-
let usdc = (usdc * 1e6).round() as u64;
227226
let wallet = wallet.unwrap_or(&self.wallet);
227+
let hyperliquid_chain = if self.http_client.is_mainnet() {
228+
"Mainnet".to_string()
229+
} else {
230+
"Testnet".to_string()
231+
};
228232

229-
let timestamp = next_nonce();
230-
231-
let action = Actions::SpotUser(SpotUser {
232-
class_transfer: ClassTransfer { usdc, to_perp },
233-
});
234-
let connection_id = action.hash(timestamp, self.vault_address)?;
235-
let action = serde_json::to_value(&action).map_err(|e| Error::JsonParse(e.to_string()))?;
236-
let is_mainnet = self.http_client.is_mainnet();
237-
let signature = sign_l1_action(wallet, connection_id, is_mainnet)?;
233+
let nonce = next_nonce();
234+
let payload = UsdClassTransfer {
235+
signature_chain_id: 421614,
236+
hyperliquid_chain,
237+
amount: format!("{}", usd_amount),
238+
to_perp,
239+
nonce,
240+
};
241+
let signature = sign_typed_data(&payload, wallet)?;
242+
let action = serde_json::to_value(Actions::UsdClassTransfer(payload))
243+
.map_err(|e| Error::JsonParse(e.to_string()))?;
238244

239-
self.post(action, signature, timestamp).await
245+
self.post(action, signature, nonce).await
240246
}
241247

242248
pub async fn send_asset(

0 commit comments

Comments
 (0)