df_elysium_core/client/
method.rs1use df_hyperliquid_core::client::evm::abi::{self, AbiError, Token};
6
7use crate::utils::{Address, keccak256};
8use crate::{B256, U256};
9
10const WORD: usize = 32;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Method {
15 pub signature: &'static str,
17 pub returns: &'static str,
19}
20
21impl Method {
22 #[must_use]
23 pub const fn new(signature: &'static str, returns: &'static str) -> Method {
24 Method { signature, returns }
25 }
26
27 #[must_use]
29 pub fn selector(&self) -> [u8; 4] {
30 let hash = keccak256(self.signature.as_bytes());
31 [hash[0], hash[1], hash[2], hash[3]]
32 }
33
34 #[must_use]
37 pub fn calldata(&self, args: &[Arg<'_>]) -> Vec<u8> {
38 let heads = args.len() * WORD;
39 let mut head = Vec::with_capacity(4 + heads);
40 head.extend_from_slice(&self.selector());
41 let mut tail = Vec::new();
42 for arg in args {
43 match arg {
44 Arg::Address(address) => head.extend_from_slice(&B256::from_address(*address).0),
45 Arg::Uint(value) => head.extend_from_slice(&value.to_be_bytes()),
46 Arg::Word(word) => head.extend_from_slice(&word.0),
47 Arg::Bool(value) => head.extend_from_slice(&count(usize::from(*value))),
48 Arg::Bytes(bytes) => {
49 head.extend_from_slice(&count(heads + tail.len()));
50 tail.extend_from_slice(&count(bytes.len()));
51 tail.extend_from_slice(bytes);
52 tail.resize(tail.len() + bytes.len().next_multiple_of(WORD) - bytes.len(), 0);
53 }
54 Arg::Words(words) => {
55 head.extend_from_slice(&count(heads + tail.len()));
56 tail.extend_from_slice(&count(words.len()));
57 for word in *words {
58 tail.extend_from_slice(&word.0);
59 }
60 }
61 }
62 }
63 head.extend(tail);
64 head
65 }
66
67 pub fn answer(&self, data: &[u8]) -> Result<Vec<Token>, AbiError> {
69 abi::decode(&abi::params(self.returns)?, data)
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub enum Arg<'a> {
77 Address(Address),
78 Uint(U256),
79 Word(B256),
80 Bool(bool),
81 Bytes(&'a [u8]),
82 Words(&'a [B256]),
83}
84
85impl Arg<'_> {
86 #[must_use]
88 pub const fn u64(value: u64) -> Arg<'static> {
89 Arg::Uint(U256::from_u64(value))
90 }
91}
92
93fn count(value: usize) -> [u8; WORD] {
94 U256::from_u64(value as u64).to_be_bytes()
95}
96
97#[cfg(test)]
98#[path = "tests/method.rs"]
99mod tests;