df_hyperliquid_core/utils/sign/
l1.rs1use crate::account::signer::Signature;
6use crate::client::body;
7use crate::client::network::Network;
8use crate::utils::address::Address;
9use crate::utils::sign::eip712::{Domain, Field, TypedStruct};
10use crate::utils::sign::keccak::Keccak256;
11use crate::utils::sign::msgpack::Map;
12
13#[must_use]
16pub fn connection_id(msgpack: &[u8], nonce: u64, vault: Option<Address>) -> [u8; 32] {
17 let sponge = Keccak256::new().chain(msgpack).chain(&nonce.to_be_bytes());
18 match vault {
19 Some(vault) => sponge.chain(&[0x01]).chain(vault.bytes()),
20 None => sponge.chain(&[0x00]),
21 }
22 .finalize()
23}
24
25#[must_use]
27pub fn phantom_agent(connection_id: [u8; 32], network: Network) -> TypedStruct<'static> {
28 TypedStruct::new("Agent")
29 .field("source", Field::String(network.agent_source()))
30 .field("connectionId", Field::Bytes32(connection_id))
31}
32
33#[must_use]
35pub fn l1_digest(msgpack: &[u8], nonce: u64, vault: Option<Address>, network: Network) -> [u8; 32] {
36 phantom_agent(connection_id(msgpack, nonce, vault), network).digest(&Domain::EXCHANGE)
37}
38
39pub trait L1Action {
43 fn action(&self) -> Map;
45
46 #[must_use]
47 fn msgpack(&self) -> Vec<u8> {
48 self.action().to_msgpack()
49 }
50
51 #[must_use]
53 fn wire(&self) -> String {
54 self.action().to_json().compact()
55 }
56
57 #[must_use]
58 fn connection_id(&self, nonce: u64, vault: Option<Address>) -> [u8; 32] {
59 connection_id(&self.msgpack(), nonce, vault)
60 }
61
62 #[must_use]
63 fn typed(&self, nonce: u64, vault: Option<Address>, network: Network) -> TypedStruct<'static> {
64 phantom_agent(self.connection_id(nonce, vault), network)
65 }
66
67 #[must_use]
68 fn digest(&self, nonce: u64, vault: Option<Address>, network: Network) -> [u8; 32] {
69 self.typed(nonce, vault, network).digest(&Domain::EXCHANGE)
70 }
71
72 #[must_use]
74 fn wallet_json(&self, nonce: u64, vault: Option<Address>, network: Network) -> String {
75 self.typed(nonce, vault, network).wallet_json(&Domain::EXCHANGE)
76 }
77
78 #[must_use]
79 fn body(&self, nonce: u64, signature: &Signature, vault: Option<Address>) -> String {
80 body::l1(&self.action(), nonce, signature, vault)
81 }
82}
83
84impl L1Action for Map {
86 fn action(&self) -> Map {
87 self.clone()
88 }
89}
90
91#[cfg(test)]
92#[path = "tests/l1.rs"]
93mod tests;