df_hyperliquid_core/client/evm/abi/
text.rs1use crate::client::evm::abi::kind::split;
5use crate::client::evm::abi::token::negated;
6use crate::client::evm::abi::{AbiError, Kind, Token, WORD};
7use crate::client::evm::u256::U256;
8use crate::utils::hex;
9
10impl Token {
11 pub fn parse(kind: &Kind, name: &str, text: &str) -> Result<Token, AbiError> {
15 let text = text.trim();
16 let refused = || AbiError::Value { name: name.to_owned(), wants: kind.wants(), got: text.to_owned() };
17 Ok(match kind {
18 Kind::Uint(bits) => {
19 let value = U256::from_decimal(text).map_err(|_| refused())?;
20 if value.bits() > u32::from(*bits) {
21 return Err(refused());
22 }
23 Token::Uint(value)
24 }
25 Kind::Int(bits) => {
26 let (negative, digits) = match text.strip_prefix('-') {
27 Some(rest) => (true, rest),
28 None => (false, text),
29 };
30 let magnitude = U256::from_decimal(digits).map_err(|_| refused())?;
31 let room = u32::from(*bits) - 1;
34 let edge = magnitude.bits() == room + 1 && magnitude == power_of_two(room);
35 if magnitude.bits() > room && !(negative && edge) {
36 return Err(refused());
37 }
38 Token::Int(match negative {
39 true => negated(magnitude),
40 false => magnitude,
41 })
42 }
43 Kind::Address => Token::Address(text.parse().map_err(|_| refused())?),
44 Kind::Bool => match text.to_ascii_lowercase().as_str() {
45 "true" => Token::Bool(true),
46 "false" => Token::Bool(false),
47 _ => return Err(refused()),
48 },
49 Kind::String => Token::String(text.to_owned()),
50 Kind::Bytes => Token::Bytes(hex_of(text).ok_or_else(refused)?),
51 Kind::Fixed(size) => Token::Fixed(hex_of(text).filter(|bytes| bytes.len() == *size).ok_or_else(refused)?),
52 Kind::Array(inner) | Kind::Sized(inner, _) => {
53 let inside = text.strip_prefix('[').and_then(|rest| rest.strip_suffix(']')).ok_or_else(refused)?;
54 let items: Vec<&str> = match inside.trim().is_empty() {
55 true => Vec::new(),
56 false => split(inside),
57 };
58 if let Kind::Sized(_, count) = kind
59 && items.len() != *count
60 {
61 return Err(refused());
62 }
63 Token::Array(items.iter().map(|item| Token::parse(inner, name, item)).collect::<Result<_, _>>()?)
64 }
65 Kind::Tuple(params) => {
66 let inside = text.strip_prefix('(').and_then(|rest| rest.strip_suffix(')')).ok_or_else(refused)?;
67 let items = split(inside);
68 if items.len() != params.len() {
69 return Err(refused());
70 }
71 Token::Tuple(
72 params
73 .iter()
74 .zip(items)
75 .map(|(param, item)| Token::parse(¶m.kind, param.name.as_deref().unwrap_or(name), item))
76 .collect::<Result<_, _>>()?,
77 )
78 }
79 })
80 }
81
82 #[must_use]
85 pub fn show(&self, kind: &Kind) -> String {
86 match (self, kind) {
87 (Token::Uint(value), _) => value.to_string(),
88 (Token::Int(value), _) => signed(*value),
89 (Token::Address(address), _) => address.to_hex(),
90 (Token::Bool(value), _) => value.to_string(),
91 (Token::String(text), _) => text.clone(),
92 (Token::Bytes(bytes) | Token::Fixed(bytes), _) => hex::encode_prefixed(bytes),
93 (Token::Array(items), Kind::Array(inner) | Kind::Sized(inner, _)) => {
94 format!("[{}]", items.iter().map(|item| item.show(inner)).collect::<Vec<_>>().join(", "))
95 }
96 (Token::Tuple(items), Kind::Tuple(params)) => format!(
97 "{{{}}}",
98 items
99 .iter()
100 .zip(params)
101 .map(|(item, param)| match ¶m.name {
102 Some(name) => format!("{name}: {}", item.show(¶m.kind)),
103 None => item.show(¶m.kind),
104 })
105 .collect::<Vec<_>>()
106 .join(", ")
107 ),
108 (Token::Array(items) | Token::Tuple(items), _) => {
109 format!("[{}]", items.iter().map(|item| item.show(kind)).collect::<Vec<_>>().join(", "))
110 }
111 }
112 }
113
114 pub(super) fn describe(&self) -> String {
116 match self {
117 Token::Uint(value) => format!("the number {value}"),
118 Token::Int(value) => format!("the number {}", signed(*value)),
119 Token::Address(address) => format!("the address {address}"),
120 Token::Bool(value) => format!("{value}"),
121 Token::String(_) => "a string".to_owned(),
122 Token::Bytes(bytes) => format!("{} bytes", bytes.len()),
123 Token::Fixed(bytes) => format!("{} fixed bytes", bytes.len()),
124 Token::Array(items) => format!("a list of {}", items.len()),
125 Token::Tuple(items) => format!("a tuple of {}", items.len()),
126 }
127 }
128}
129
130fn power_of_two(exponent: u32) -> U256 {
131 let mut word = [0u8; WORD];
132 let at = WORD - 1 - (exponent / 8) as usize;
133 word[at] = 1 << (exponent % 8);
134 U256::from_be_bytes(word)
135}
136
137fn signed(value: U256) -> String {
139 match value.bits() == 256 {
140 true => format!("-{}", negated(value)),
141 false => value.to_string(),
142 }
143}
144
145fn hex_of(text: &str) -> Option<Vec<u8>> {
146 text.strip_prefix("0x").or_else(|| text.strip_prefix("0X"))?;
147 hex::decode(text).ok()
148}
149
150#[cfg(test)]
151#[path = "tests/text.rs"]
152mod tests;