Skip to main content

df_hyperliquid_core/client/evm/abi/
token.rs

1//! A [`Token`], a value of some [`Kind`](crate::client::evm::abi::Kind): built
2//! from Rust values and read back into them, signed integers in two's complement.
3
4use crate::client::evm::u256::U256;
5use crate::utils::Address;
6
7/// A value of some [`Kind`](crate::client::evm::abi::Kind).
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Token {
10    Uint(U256),
11    /// Two's complement in 256 bits: -1 is all ones, whatever the width.
12    Int(U256),
13    Address(Address),
14    Bool(bool),
15    String(String),
16    Bytes(Vec<u8>),
17    /// The `n` bytes of a `bytesN`.
18    Fixed(Vec<u8>),
19    /// `T[]` and `T[n]`.
20    Array(Vec<Token>),
21    Tuple(Vec<Token>),
22}
23
24impl Token {
25    #[must_use]
26    pub fn uint(value: impl Into<U256>) -> Token {
27        Token::Uint(value.into())
28    }
29
30    #[must_use]
31    pub fn int(value: i128) -> Token {
32        let magnitude = U256::from_u128(value.unsigned_abs());
33        Token::Int(match value < 0 {
34            true => negated(magnitude),
35            false => magnitude,
36        })
37    }
38
39    #[must_use]
40    pub fn address(address: Address) -> Token {
41        Token::Address(address)
42    }
43
44    #[must_use]
45    pub fn as_u256(&self) -> Option<U256> {
46        match self {
47            Token::Uint(value) => Some(*value),
48            _ => None,
49        }
50    }
51
52    #[must_use]
53    pub fn as_u128(&self) -> Option<u128> {
54        self.as_u256().and_then(U256::to_u128)
55    }
56
57    #[must_use]
58    pub fn as_u64(&self) -> Option<u64> {
59        self.as_u256().and_then(U256::to_u64)
60    }
61
62    #[must_use]
63    pub fn as_u32(&self) -> Option<u32> {
64        self.as_u64().and_then(|value| u32::try_from(value).ok())
65    }
66
67    #[must_use]
68    pub fn as_u16(&self) -> Option<u16> {
69        self.as_u64().and_then(|value| u16::try_from(value).ok())
70    }
71
72    #[must_use]
73    pub fn as_u8(&self) -> Option<u8> {
74        self.as_u64().and_then(|value| u8::try_from(value).ok())
75    }
76
77    /// A signed integer, while it fits an `i128`.
78    #[must_use]
79    pub fn as_i128(&self) -> Option<i128> {
80        let Token::Int(value) = self else { return None };
81        match value.bits() == 256 {
82            false => value.to_u128().and_then(|value| i128::try_from(value).ok()),
83            true => {
84                let magnitude = negated(*value).to_u128()?;
85                match magnitude == i128::MIN.unsigned_abs() {
86                    true => Some(i128::MIN),
87                    false => i128::try_from(magnitude).ok().map(|magnitude| -magnitude),
88                }
89            }
90        }
91    }
92
93    #[must_use]
94    pub fn as_i64(&self) -> Option<i64> {
95        self.as_i128().and_then(|value| i64::try_from(value).ok())
96    }
97
98    #[must_use]
99    pub fn as_i8(&self) -> Option<i8> {
100        self.as_i128().and_then(|value| i8::try_from(value).ok())
101    }
102
103    #[must_use]
104    pub fn as_address(&self) -> Option<Address> {
105        match self {
106            Token::Address(address) => Some(*address),
107            _ => None,
108        }
109    }
110
111    #[must_use]
112    pub fn as_bool(&self) -> Option<bool> {
113        match self {
114            Token::Bool(value) => Some(*value),
115            _ => None,
116        }
117    }
118
119    #[must_use]
120    pub fn as_str(&self) -> Option<&str> {
121        match self {
122            Token::String(text) => Some(text),
123            _ => None,
124        }
125    }
126
127    /// The bytes of a `bytes` or a `bytesN`.
128    #[must_use]
129    pub fn as_bytes(&self) -> Option<&[u8]> {
130        match self {
131            Token::Bytes(bytes) | Token::Fixed(bytes) => Some(bytes),
132            _ => None,
133        }
134    }
135
136    /// The items of an array or the fields of a tuple.
137    #[must_use]
138    pub fn as_items(&self) -> Option<&[Token]> {
139        match self {
140            Token::Array(items) | Token::Tuple(items) => Some(items),
141            _ => None,
142        }
143    }
144}
145
146/// `-value` in two's complement: `2^256 - value`, and zero for zero.
147pub(super) fn negated(value: U256) -> U256 {
148    match value.checked_sub(U256::ONE) {
149        Some(less) => U256::MAX.checked_sub(less).unwrap_or(U256::ZERO),
150        None => U256::ZERO,
151    }
152}