hyperliquid_sdk_rs/types/
eip712.rs1use alloy::primitives::{keccak256, Address, B256, U256};
2use alloy::sol_types::Eip712Domain;
3
4pub trait HyperliquidAction: Sized + serde::Serialize {
5 const TYPE_STRING: &'static str;
7
8 const USE_PREFIX: bool = true;
10
11 fn chain_id(&self) -> Option<u64> {
14 None
15 }
16
17 fn domain(&self) -> Eip712Domain {
19 let chain_id = self.chain_id().unwrap_or(1); alloy::sol_types::eip712_domain! {
21 name: "HyperliquidSignTransaction",
22 version: "1",
23 chain_id: chain_id,
24 verifying_contract: alloy::primitives::address!("0000000000000000000000000000000000000000"),
25 }
26 }
27
28 fn type_hash() -> B256 {
29 let type_string = if Self::USE_PREFIX {
30 format!("HyperliquidTransaction:{}", Self::TYPE_STRING)
31 } else {
32 Self::TYPE_STRING.to_string()
33 };
34 keccak256(type_string.as_bytes())
35 }
36
37 fn encode_data(&self) -> Vec<u8> {
40 let mut encoded = Vec::new();
43 encoded.extend_from_slice(&Self::type_hash()[..]);
44 encoded
46 }
47
48 fn struct_hash(&self) -> B256 {
49 keccak256(self.encode_data())
50 }
51
52 fn eip712_signing_hash(&self, domain: &Eip712Domain) -> B256 {
53 let domain_separator = domain.separator();
54 let struct_hash = self.struct_hash();
55
56 let mut buf = Vec::with_capacity(66);
57 buf.push(0x19);
58 buf.push(0x01);
59 buf.extend_from_slice(&domain_separator[..]);
60 buf.extend_from_slice(&struct_hash[..]);
61
62 keccak256(&buf)
63 }
64}
65
66pub fn encode_value<T: EncodeEip712>(value: &T) -> [u8; 32] {
68 value.encode_eip712()
69}
70
71pub trait EncodeEip712 {
73 fn encode_eip712(&self) -> [u8; 32];
74}
75
76impl EncodeEip712 for String {
77 fn encode_eip712(&self) -> [u8; 32] {
78 keccak256(self.as_bytes()).into()
79 }
80}
81
82impl EncodeEip712 for u64 {
83 fn encode_eip712(&self) -> [u8; 32] {
84 U256::from(*self).to_be_bytes::<32>()
85 }
86}
87
88impl EncodeEip712 for B256 {
89 fn encode_eip712(&self) -> [u8; 32] {
90 (*self).into()
91 }
92}
93
94impl EncodeEip712 for Address {
95 fn encode_eip712(&self) -> [u8; 32] {
96 let mut result = [0u8; 32];
97 result[12..].copy_from_slice(self.as_slice());
98 result
99 }
100}
101
102impl<T: EncodeEip712> EncodeEip712 for Option<T> {
103 fn encode_eip712(&self) -> [u8; 32] {
104 match self {
105 Some(v) => v.encode_eip712(),
106 None => keccak256("".as_bytes()).into(), }
108 }
109}