1use std::fmt;
6
7use crate::client::evm::u256::{B256, U256};
8use crate::utils::sign::keccak256;
9use crate::utils::{Address, hex};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Kind {
13 Uint(u16),
14 Int(u16),
15 Address,
16 Bool,
17 String,
18 Bytes,
19 Fixed(usize),
21 Array(Box<Kind>),
23 Sized(Box<Kind>, usize),
25 Tuple(Vec<Param>),
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Param {
31 pub name: Option<String>,
32 pub kind: Kind,
33 pub indexed: bool,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum Token {
39 Uint(U256),
40 Int(U256),
42 Address(Address),
43 Bool(bool),
44 String(String),
45 Bytes(Vec<u8>),
46 Fixed(Vec<u8>),
48 Array(Vec<Token>),
50 Tuple(Vec<Token>),
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
54pub enum AbiError {
55 #[error("`{0}` is not a type this reads")]
56 Type(String),
57 #[error("`{0}` is not a signature this reads; expected name(types)")]
58 Signature(String),
59 #[error("{name} must be {wants}, and `{got}` is not")]
60 Value { name: String, wants: String, got: String },
61 #[error("expected {wants} values and there are {got}")]
62 Count { wants: usize, got: usize },
63 #[error("a {kind} cannot hold {token}")]
64 Mismatch { kind: String, token: String },
65 #[error("the data ends at byte {0}, before the shape it was declared with")]
66 Short(usize),
67 #[error("the word at byte {at} does not fit {kind}")]
68 Misfit { at: usize, kind: String },
69 #[error("the calldata is for selector {found}, not {wants}")]
70 Selector { wants: String, found: String },
71}
72
73const WORD: usize = 32;
74
75const LONGEST: usize = 1 << 20;
77
78const DEEPEST: usize = 32;
80
81const MODIFIERS: [&str; 4] = ["memory", "calldata", "storage", "payable"];
83
84impl Kind {
85 pub fn parse(text: &str) -> Result<Kind, AbiError> {
87 kind_of(text, 0).ok_or_else(|| AbiError::Type(text.trim().to_owned()))
88 }
89
90 #[must_use]
92 pub fn is_dynamic(&self) -> bool {
93 match self {
94 Kind::String | Kind::Bytes | Kind::Array(_) => true,
95 Kind::Sized(inner, _) => inner.is_dynamic(),
96 Kind::Tuple(params) => params.iter().any(|param| param.kind.is_dynamic()),
97 Kind::Uint(_) | Kind::Int(_) | Kind::Address | Kind::Bool | Kind::Fixed(_) => false,
98 }
99 }
100
101 fn head(&self) -> usize {
103 if self.is_dynamic() {
104 return WORD;
105 }
106 match self {
107 Kind::Sized(inner, count) => inner.head().saturating_mul(*count),
108 Kind::Tuple(params) => params.iter().map(|param| param.kind.head()).sum(),
109 _ => WORD,
110 }
111 }
112
113 #[must_use]
115 pub fn canonical(&self) -> String {
116 match self {
117 Kind::Uint(bits) => format!("uint{bits}"),
118 Kind::Int(bits) => format!("int{bits}"),
119 Kind::Address => "address".to_owned(),
120 Kind::Bool => "bool".to_owned(),
121 Kind::String => "string".to_owned(),
122 Kind::Bytes => "bytes".to_owned(),
123 Kind::Fixed(size) => format!("bytes{size}"),
124 Kind::Array(inner) => format!("{}[]", inner.canonical()),
125 Kind::Sized(inner, count) => format!("{}[{count}]", inner.canonical()),
126 Kind::Tuple(params) => tuple_type(params),
127 }
128 }
129
130 fn wants(&self) -> String {
132 match self {
133 Kind::Uint(bits) => format!("a whole number that fits uint{bits}"),
134 Kind::Int(bits) => format!("a whole number that fits int{bits}"),
135 Kind::Address => "a 20-byte address".to_owned(),
136 Kind::Bool => "true or false".to_owned(),
137 Kind::String => "text".to_owned(),
138 Kind::Bytes => "hex bytes".to_owned(),
139 Kind::Fixed(size) => format!("{size} hex bytes"),
140 Kind::Array(_) | Kind::Sized(..) => "a list in brackets".to_owned(),
141 Kind::Tuple(_) => "a tuple in parentheses".to_owned(),
142 }
143 }
144}
145
146impl fmt::Display for Kind {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.write_str(&self.canonical())
149 }
150}
151
152#[must_use]
154pub fn tuple_type(params: &[Param]) -> String {
155 let kinds: Vec<String> = params.iter().map(|param| param.kind.canonical()).collect();
156 format!("({})", kinds.join(","))
157}
158
159pub fn params(text: &str) -> Result<Vec<Param>, AbiError> {
162 params_at(text, 0).ok_or_else(|| AbiError::Type(text.trim().to_owned()))
163}
164
165fn params_at(text: &str, depth: usize) -> Option<Vec<Param>> {
166 let text = text.trim();
167 if text.is_empty() {
168 return Some(Vec::new());
169 }
170 split(text).into_iter().map(|one| param(one.trim(), depth)).collect()
171}
172
173fn param(text: &str, depth: usize) -> Option<Param> {
175 let end = type_end(text);
176 let kind = kind_of(&text[..end], depth)?;
177 let mut name = None;
178 let mut indexed = false;
179 for word in text[end..].split_whitespace() {
180 match word {
181 "indexed" => indexed = true,
182 _ if MODIFIERS.contains(&word) => {}
183 _ if name.is_none() && is_name(word) => name = Some(word.to_owned()),
184 _ => return None,
185 }
186 }
187 Some(Param { name, kind, indexed })
188}
189
190fn is_name(word: &str) -> bool {
191 word.chars().all(|letter| letter.is_ascii_alphanumeric() || letter == '_' || letter == '$')
192}
193
194fn type_end(text: &str) -> usize {
196 let mut depth = 0i32;
197 for (at, letter) in text.char_indices() {
198 match letter {
199 '(' | '[' => depth += 1,
200 ')' | ']' => depth -= 1,
201 _ if letter.is_whitespace() && depth == 0 => return at,
202 _ => {}
203 }
204 }
205 text.len()
206}
207
208fn depth_at(text: &str, at: usize) -> i32 {
209 text[..at].chars().fold(0, |depth, letter| match letter {
210 '(' | '[' => depth + 1,
211 ')' | ']' => depth - 1,
212 _ => depth,
213 })
214}
215
216fn kind_of(text: &str, depth: usize) -> Option<Kind> {
217 if depth > DEEPEST {
218 return None;
219 }
220 let text = text.trim();
221 if let Some(open) = text.rfind('[')
222 && text.ends_with(']')
223 && depth_at(text, open) == 0
224 {
225 let inner = kind_of(&text[..open], depth + 1)?;
226 let count = &text[open + 1..text.len() - 1];
227 return Some(match count.is_empty() {
228 true => Kind::Array(Box::new(inner)),
229 false => Kind::Sized(Box::new(inner), count.parse().ok().filter(|count| *count <= LONGEST)?),
230 });
231 }
232 if let Some(inside) = text.strip_prefix('(').and_then(|rest| rest.strip_suffix(')')) {
233 return params_at(inside, depth + 1).map(Kind::Tuple);
234 }
235 let bits = |digits: &str| -> Option<u16> {
236 match digits.is_empty() {
237 true => Some(256),
238 false => digits.parse().ok().filter(|bits| *bits > 0 && *bits <= 256 && bits % 8 == 0),
239 }
240 };
241 Some(match text {
242 "address" => Kind::Address,
243 "bool" => Kind::Bool,
244 "string" => Kind::String,
245 "bytes" => Kind::Bytes,
246 _ if text.starts_with("uint") => Kind::Uint(bits(&text[4..])?),
247 _ if text.starts_with("int") => Kind::Int(bits(&text[3..])?),
248 _ if text.starts_with("bytes") => {
249 let size: usize = text[5..].parse().ok()?;
250 (1..=32).contains(&size).then_some(Kind::Fixed(size))?
251 }
252 _ => return None,
253 })
254}
255
256fn split(text: &str) -> Vec<&str> {
258 let mut parts = Vec::new();
259 let mut depth = 0i32;
260 let mut start = 0;
261 for (at, letter) in text.char_indices() {
262 match letter {
263 '(' | '[' => depth += 1,
264 ')' | ']' => depth -= 1,
265 ',' if depth == 0 => {
266 parts.push(&text[start..at]);
267 start = at + 1;
268 }
269 _ => {}
270 }
271 }
272 parts.push(&text[start..]);
273 parts
274}
275
276#[derive(Debug, Clone, PartialEq, Eq)]
279pub struct Function {
280 pub name: String,
281 pub inputs: Vec<Param>,
282 pub outputs: Vec<Param>,
283}
284
285impl Function {
286 pub fn parse(text: &str) -> Result<Function, AbiError> {
287 let bad = || AbiError::Signature(text.trim().to_owned());
288 let (name, inside, rest) = signature_parts(text, "function").ok_or_else(bad)?;
289 let inputs = params(inside)?;
290 let outputs = match rest.find("returns") {
291 Some(at) => {
292 let after = rest[at + "returns".len()..].trim();
293 let inner = after.strip_prefix('(').and_then(|after| after.strip_suffix(')')).ok_or_else(bad)?;
294 params(inner)?
295 }
296 None => Vec::new(),
297 };
298 Ok(Function { name: name.to_owned(), inputs, outputs })
299 }
300
301 #[must_use]
303 pub fn signature(&self) -> String {
304 format!("{}{}", self.name, tuple_type(&self.inputs))
305 }
306
307 #[must_use]
309 pub fn selector(&self) -> [u8; 4] {
310 let hash = keccak256(self.signature().as_bytes());
311 [hash[0], hash[1], hash[2], hash[3]]
312 }
313
314 pub fn encode(&self, args: &[Token]) -> Result<Vec<u8>, AbiError> {
316 let mut out = self.selector().to_vec();
317 out.extend(encode(&self.inputs, args)?);
318 Ok(out)
319 }
320
321 pub fn decode_input(&self, calldata: &[u8]) -> Result<Vec<Token>, AbiError> {
323 let found = calldata.get(..4).ok_or(AbiError::Short(calldata.len()))?;
324 if found != self.selector() {
325 return Err(AbiError::Selector {
326 wants: hex::encode_prefixed(&self.selector()),
327 found: hex::encode_prefixed(found),
328 });
329 }
330 decode(&self.inputs, &calldata[4..])
331 }
332
333 pub fn decode_output(&self, answer: &[u8]) -> Result<Vec<Token>, AbiError> {
335 decode(&self.outputs, answer)
336 }
337}
338
339fn signature_parts<'a>(text: &'a str, keyword: &str) -> Option<(&'a str, &'a str, &'a str)> {
341 let text = text.trim();
342 let text = text.strip_prefix(keyword).filter(|rest| rest.starts_with(char::is_whitespace)).unwrap_or(text).trim();
343 let open = text.find('(')?;
344 let name = text[..open].trim();
345 if name.is_empty() || !is_name(name) {
346 return None;
347 }
348 let mut depth = 0i32;
349 for (at, letter) in text[open..].char_indices() {
350 match letter {
351 '(' => depth += 1,
352 ')' => {
353 depth -= 1;
354 if depth == 0 {
355 let close = open + at;
356 return Some((name, &text[open + 1..close], &text[close + 1..]));
357 }
358 }
359 _ => {}
360 }
361 }
362 None
363}
364
365pub fn selector(signature: &str) -> Result<[u8; 4], AbiError> {
367 Function::parse(signature).map(|function| function.selector())
368}
369
370pub fn event_topic(signature: &str) -> Result<B256, AbiError> {
372 let (name, inside, _) =
373 signature_parts(signature, "event").ok_or_else(|| AbiError::Signature(signature.trim().to_owned()))?;
374 let canonical = format!("{name}{}", tuple_type(¶ms(inside)?));
375 Ok(B256(keccak256(canonical.as_bytes())))
376}
377
378pub fn encode(params: &[Param], tokens: &[Token]) -> Result<Vec<u8>, AbiError> {
381 if params.len() != tokens.len() {
382 return Err(AbiError::Count { wants: params.len(), got: tokens.len() });
383 }
384 for (param, token) in params.iter().zip(tokens) {
385 if !fits(¶m.kind, token) {
386 return Err(AbiError::Mismatch { kind: param.kind.canonical(), token: token.describe() });
387 }
388 }
389 let kinds: Vec<&Kind> = params.iter().map(|param| ¶m.kind).collect();
390 Ok(sequence(&kinds, tokens))
391}
392
393fn fits(kind: &Kind, token: &Token) -> bool {
395 match (kind, token) {
396 (Kind::Uint(bits), Token::Uint(value)) => value.bits() <= u32::from(*bits),
397 (Kind::Int(bits), Token::Int(value)) => sign_extended(&value.to_be_bytes(), *bits),
398 (Kind::Address, Token::Address(_))
399 | (Kind::Bool, Token::Bool(_))
400 | (Kind::String, Token::String(_))
401 | (Kind::Bytes, Token::Bytes(_)) => true,
402 (Kind::Fixed(size), Token::Fixed(bytes)) => bytes.len() == *size,
403 (Kind::Array(inner), Token::Array(items)) => items.iter().all(|item| fits(inner, item)),
404 (Kind::Sized(inner, count), Token::Array(items)) => {
405 items.len() == *count && items.iter().all(|item| fits(inner, item))
406 }
407 (Kind::Tuple(params), Token::Tuple(items)) => {
408 params.len() == items.len() && params.iter().zip(items).all(|(param, item)| fits(¶m.kind, item))
409 }
410 _ => false,
411 }
412}
413
414fn sign_extended(word: &[u8; WORD], bits: u16) -> bool {
416 let spare = WORD - usize::from(bits) / 8;
417 if spare == 0 {
418 return true;
419 }
420 let fill = if word[spare] & 0x80 == 0 { 0x00 } else { 0xff };
421 word[..spare].iter().all(|byte| *byte == fill)
422}
423
424fn sequence(kinds: &[&Kind], tokens: &[Token]) -> Vec<u8> {
425 let heads: usize = kinds.iter().map(|kind| kind.head()).sum();
426 let mut head = Vec::with_capacity(heads);
427 let mut tail = Vec::new();
428 for (kind, token) in kinds.iter().zip(tokens) {
429 let encoded = one(kind, token);
430 match kind.is_dynamic() {
431 true => {
432 head.extend_from_slice(&word_of(heads + tail.len()));
433 tail.extend(encoded);
434 }
435 false => head.extend(encoded),
436 }
437 }
438 head.extend(tail);
439 head
440}
441
442fn one(kind: &Kind, token: &Token) -> Vec<u8> {
444 match (kind, token) {
445 (_, Token::Uint(value) | Token::Int(value)) => value.to_be_bytes().to_vec(),
446 (_, Token::Address(address)) => B256::from_address(*address).0.to_vec(),
447 (_, Token::Bool(value)) => word_of(usize::from(*value)).to_vec(),
448 (_, Token::String(text)) => packed(text.as_bytes()),
449 (_, Token::Bytes(bytes)) => packed(bytes),
450 (_, Token::Fixed(bytes)) => padded(bytes),
451 (Kind::Array(inner), Token::Array(items)) => {
452 let mut out = word_of(items.len()).to_vec();
453 out.extend(sequence(&vec![inner.as_ref(); items.len()], items));
454 out
455 }
456 (Kind::Sized(inner, _), Token::Array(items)) => sequence(&vec![inner.as_ref(); items.len()], items),
457 (Kind::Tuple(params), Token::Tuple(items)) => {
458 let kinds: Vec<&Kind> = params.iter().map(|param| ¶m.kind).collect();
459 sequence(&kinds, items)
460 }
461 (_, Token::Array(items) | Token::Tuple(items)) => sequence(&vec![kind; items.len()], items),
462 }
463}
464
465fn packed(bytes: &[u8]) -> Vec<u8> {
466 let mut out = word_of(bytes.len()).to_vec();
467 out.extend(padded(bytes));
468 out
469}
470
471fn padded(bytes: &[u8]) -> Vec<u8> {
472 let mut out = bytes.to_vec();
473 out.resize(bytes.len().div_ceil(WORD) * WORD, 0);
474 out
475}
476
477fn word_of(value: usize) -> [u8; WORD] {
478 U256::from_u64(value as u64).to_be_bytes()
479}
480
481pub fn decode(params: &[Param], data: &[u8]) -> Result<Vec<Token>, AbiError> {
483 let kinds: Vec<&Kind> = params.iter().map(|param| ¶m.kind).collect();
484 unsequence(&kinds, data, 0)
485}
486
487fn unsequence(kinds: &[&Kind], data: &[u8], start: usize) -> Result<Vec<Token>, AbiError> {
488 let mut at = start;
489 let mut tokens = Vec::with_capacity(kinds.len().min(LONGEST / WORD));
490 for kind in kinds {
491 match kind.is_dynamic() {
492 true => {
493 let offset = length(data, at)?;
494 tokens.push(unone(kind, data, start + offset)?);
495 at += WORD;
496 }
497 false => {
498 tokens.push(unone(kind, data, at)?);
499 at += kind.head();
500 }
501 }
502 }
503 Ok(tokens)
504}
505
506fn word(data: &[u8], at: usize) -> Result<[u8; WORD], AbiError> {
507 data.get(at..at.saturating_add(WORD)).and_then(|slice| slice.try_into().ok()).ok_or(AbiError::Short(data.len()))
508}
509
510fn length(data: &[u8], at: usize) -> Result<usize, AbiError> {
512 let value = U256::from_be_bytes(word(data, at)?);
513 value
514 .to_u64()
515 .and_then(|value| usize::try_from(value).ok())
516 .filter(|value| *value <= LONGEST)
517 .ok_or_else(|| AbiError::Misfit { at, kind: "a length".to_owned() })
518}
519
520fn unone(kind: &Kind, data: &[u8], at: usize) -> Result<Token, AbiError> {
521 let misfit = || AbiError::Misfit { at, kind: kind.canonical() };
522 Ok(match kind {
523 Kind::Uint(bits) => {
524 let value = U256::from_be_bytes(word(data, at)?);
525 if value.bits() > u32::from(*bits) {
526 return Err(misfit());
527 }
528 Token::Uint(value)
529 }
530 Kind::Int(bits) => {
531 let word = word(data, at)?;
532 if !sign_extended(&word, *bits) {
533 return Err(misfit());
534 }
535 Token::Int(U256::from_be_bytes(word))
536 }
537 Kind::Address => B256(word(data, at)?).to_address().map(Token::Address).ok_or_else(misfit)?,
538 Kind::Bool => match U256::from_be_bytes(word(data, at)?).to_u64() {
539 Some(0) => Token::Bool(false),
540 Some(1) => Token::Bool(true),
541 _ => return Err(misfit()),
542 },
543 Kind::Fixed(size) => {
544 let word = word(data, at)?;
545 if word[*size..].iter().any(|byte| *byte != 0) {
546 return Err(misfit());
547 }
548 Token::Fixed(word[..*size].to_vec())
549 }
550 Kind::String | Kind::Bytes => {
551 let length = length(data, at)?;
552 let start = at + WORD;
553 let bytes = data.get(start..start + length).ok_or(AbiError::Short(data.len()))?.to_vec();
554 match kind {
555 Kind::String => Token::String(String::from_utf8(bytes).map_err(|_| misfit())?),
556 _ => Token::Bytes(bytes),
557 }
558 }
559 Kind::Array(inner) => {
560 let count = length(data, at)?;
561 if count.saturating_mul(inner.head().max(1)) > data.len() {
562 return Err(AbiError::Short(data.len()));
563 }
564 Token::Array(unsequence(&vec![inner.as_ref(); count], data, at + WORD)?)
565 }
566 Kind::Sized(inner, count) => {
567 if count.saturating_mul(inner.head().max(1)) > data.len() {
568 return Err(AbiError::Short(data.len()));
569 }
570 Token::Array(unsequence(&vec![inner.as_ref(); *count], data, at)?)
571 }
572 Kind::Tuple(params) => {
573 let kinds: Vec<&Kind> = params.iter().map(|param| ¶m.kind).collect();
574 Token::Tuple(unsequence(&kinds, data, at)?)
575 }
576 })
577}
578
579impl Token {
580 #[must_use]
581 pub fn uint(value: impl Into<U256>) -> Token {
582 Token::Uint(value.into())
583 }
584
585 #[must_use]
586 pub fn int(value: i128) -> Token {
587 let magnitude = U256::from_u128(value.unsigned_abs());
588 Token::Int(match value < 0 {
589 true => negated(magnitude),
590 false => magnitude,
591 })
592 }
593
594 #[must_use]
595 pub fn address(address: Address) -> Token {
596 Token::Address(address)
597 }
598
599 pub fn parse(kind: &Kind, name: &str, text: &str) -> Result<Token, AbiError> {
603 let text = text.trim();
604 let refused = || AbiError::Value { name: name.to_owned(), wants: kind.wants(), got: text.to_owned() };
605 Ok(match kind {
606 Kind::Uint(bits) => {
607 let value = U256::from_decimal(text).map_err(|_| refused())?;
608 if value.bits() > u32::from(*bits) {
609 return Err(refused());
610 }
611 Token::Uint(value)
612 }
613 Kind::Int(bits) => {
614 let (negative, digits) = match text.strip_prefix('-') {
615 Some(rest) => (true, rest),
616 None => (false, text),
617 };
618 let magnitude = U256::from_decimal(digits).map_err(|_| refused())?;
619 let room = u32::from(*bits) - 1;
622 let edge = magnitude.bits() == room + 1 && magnitude == power_of_two(room);
623 if magnitude.bits() > room && !(negative && edge) {
624 return Err(refused());
625 }
626 Token::Int(match negative {
627 true => negated(magnitude),
628 false => magnitude,
629 })
630 }
631 Kind::Address => Token::Address(text.parse().map_err(|_| refused())?),
632 Kind::Bool => match text.to_ascii_lowercase().as_str() {
633 "true" => Token::Bool(true),
634 "false" => Token::Bool(false),
635 _ => return Err(refused()),
636 },
637 Kind::String => Token::String(text.to_owned()),
638 Kind::Bytes => Token::Bytes(hex_of(text).ok_or_else(refused)?),
639 Kind::Fixed(size) => Token::Fixed(hex_of(text).filter(|bytes| bytes.len() == *size).ok_or_else(refused)?),
640 Kind::Array(inner) | Kind::Sized(inner, _) => {
641 let inside = text.strip_prefix('[').and_then(|rest| rest.strip_suffix(']')).ok_or_else(refused)?;
642 let items: Vec<&str> = match inside.trim().is_empty() {
643 true => Vec::new(),
644 false => split(inside),
645 };
646 if let Kind::Sized(_, count) = kind
647 && items.len() != *count
648 {
649 return Err(refused());
650 }
651 Token::Array(items.iter().map(|item| Token::parse(inner, name, item)).collect::<Result<_, _>>()?)
652 }
653 Kind::Tuple(params) => {
654 let inside = text.strip_prefix('(').and_then(|rest| rest.strip_suffix(')')).ok_or_else(refused)?;
655 let items = split(inside);
656 if items.len() != params.len() {
657 return Err(refused());
658 }
659 Token::Tuple(
660 params
661 .iter()
662 .zip(items)
663 .map(|(param, item)| Token::parse(¶m.kind, param.name.as_deref().unwrap_or(name), item))
664 .collect::<Result<_, _>>()?,
665 )
666 }
667 })
668 }
669
670 #[must_use]
673 pub fn show(&self, kind: &Kind) -> String {
674 match (self, kind) {
675 (Token::Uint(value), _) => value.to_string(),
676 (Token::Int(value), _) => signed(*value),
677 (Token::Address(address), _) => address.to_hex(),
678 (Token::Bool(value), _) => value.to_string(),
679 (Token::String(text), _) => text.clone(),
680 (Token::Bytes(bytes) | Token::Fixed(bytes), _) => hex::encode_prefixed(bytes),
681 (Token::Array(items), Kind::Array(inner) | Kind::Sized(inner, _)) => {
682 format!("[{}]", items.iter().map(|item| item.show(inner)).collect::<Vec<_>>().join(", "))
683 }
684 (Token::Tuple(items), Kind::Tuple(params)) => format!(
685 "{{{}}}",
686 items
687 .iter()
688 .zip(params)
689 .map(|(item, param)| match ¶m.name {
690 Some(name) => format!("{name}: {}", item.show(¶m.kind)),
691 None => item.show(¶m.kind),
692 })
693 .collect::<Vec<_>>()
694 .join(", ")
695 ),
696 (Token::Array(items) | Token::Tuple(items), _) => {
697 format!("[{}]", items.iter().map(|item| item.show(kind)).collect::<Vec<_>>().join(", "))
698 }
699 }
700 }
701
702 fn describe(&self) -> String {
704 match self {
705 Token::Uint(value) => format!("the number {value}"),
706 Token::Int(value) => format!("the number {}", signed(*value)),
707 Token::Address(address) => format!("the address {address}"),
708 Token::Bool(value) => format!("{value}"),
709 Token::String(_) => "a string".to_owned(),
710 Token::Bytes(bytes) => format!("{} bytes", bytes.len()),
711 Token::Fixed(bytes) => format!("{} fixed bytes", bytes.len()),
712 Token::Array(items) => format!("a list of {}", items.len()),
713 Token::Tuple(items) => format!("a tuple of {}", items.len()),
714 }
715 }
716
717 #[must_use]
718 pub fn as_u256(&self) -> Option<U256> {
719 match self {
720 Token::Uint(value) => Some(*value),
721 _ => None,
722 }
723 }
724
725 #[must_use]
726 pub fn as_u128(&self) -> Option<u128> {
727 self.as_u256().and_then(U256::to_u128)
728 }
729
730 #[must_use]
731 pub fn as_u64(&self) -> Option<u64> {
732 self.as_u256().and_then(U256::to_u64)
733 }
734
735 #[must_use]
736 pub fn as_u32(&self) -> Option<u32> {
737 self.as_u64().and_then(|value| u32::try_from(value).ok())
738 }
739
740 #[must_use]
741 pub fn as_u16(&self) -> Option<u16> {
742 self.as_u64().and_then(|value| u16::try_from(value).ok())
743 }
744
745 #[must_use]
746 pub fn as_u8(&self) -> Option<u8> {
747 self.as_u64().and_then(|value| u8::try_from(value).ok())
748 }
749
750 #[must_use]
752 pub fn as_i128(&self) -> Option<i128> {
753 let Token::Int(value) = self else { return None };
754 match value.bits() == 256 {
755 false => value.to_u128().and_then(|value| i128::try_from(value).ok()),
756 true => {
757 let magnitude = negated(*value).to_u128()?;
758 match magnitude == i128::MIN.unsigned_abs() {
759 true => Some(i128::MIN),
760 false => i128::try_from(magnitude).ok().map(|magnitude| -magnitude),
761 }
762 }
763 }
764 }
765
766 #[must_use]
767 pub fn as_i64(&self) -> Option<i64> {
768 self.as_i128().and_then(|value| i64::try_from(value).ok())
769 }
770
771 #[must_use]
772 pub fn as_i8(&self) -> Option<i8> {
773 self.as_i128().and_then(|value| i8::try_from(value).ok())
774 }
775
776 #[must_use]
777 pub fn as_address(&self) -> Option<Address> {
778 match self {
779 Token::Address(address) => Some(*address),
780 _ => None,
781 }
782 }
783
784 #[must_use]
785 pub fn as_bool(&self) -> Option<bool> {
786 match self {
787 Token::Bool(value) => Some(*value),
788 _ => None,
789 }
790 }
791
792 #[must_use]
793 pub fn as_str(&self) -> Option<&str> {
794 match self {
795 Token::String(text) => Some(text),
796 _ => None,
797 }
798 }
799
800 #[must_use]
802 pub fn as_bytes(&self) -> Option<&[u8]> {
803 match self {
804 Token::Bytes(bytes) | Token::Fixed(bytes) => Some(bytes),
805 _ => None,
806 }
807 }
808
809 #[must_use]
811 pub fn as_items(&self) -> Option<&[Token]> {
812 match self {
813 Token::Array(items) | Token::Tuple(items) => Some(items),
814 _ => None,
815 }
816 }
817}
818
819fn negated(value: U256) -> U256 {
821 match value.checked_sub(U256::ONE) {
822 Some(less) => U256::MAX.checked_sub(less).unwrap_or(U256::ZERO),
823 None => U256::ZERO,
824 }
825}
826
827fn power_of_two(exponent: u32) -> U256 {
828 let mut word = [0u8; WORD];
829 let at = WORD - 1 - (exponent / 8) as usize;
830 word[at] = 1 << (exponent % 8);
831 U256::from_be_bytes(word)
832}
833
834fn signed(value: U256) -> String {
836 match value.bits() == 256 {
837 true => format!("-{}", negated(value)),
838 false => value.to_string(),
839 }
840}
841
842fn hex_of(text: &str) -> Option<Vec<u8>> {
843 text.strip_prefix("0x").or_else(|| text.strip_prefix("0X"))?;
844 hex::decode(text).ok()
845}
846
847#[cfg(test)]
848#[path = "tests/abi.rs"]
849mod tests;