ethers_core/abi/
codec.rs

1use crate::{
2    abi::{
3        AbiArrayType, AbiError, AbiType, Detokenize, Token, Tokenizable, TokenizableItem, Tokenize,
4    },
5    types::{Address, Bytes, Uint8, H256, I256, U128, U256},
6};
7
8/// Trait for ABI encoding
9pub trait AbiEncode {
10    /// ABI encode the type
11    fn encode(self) -> Vec<u8>;
12
13    /// Returns the encoded value as hex string, _with_ a `0x` prefix
14    fn encode_hex(self) -> String
15    where
16        Self: Sized,
17    {
18        hex::encode_prefixed(self.encode())
19    }
20}
21
22/// Trait for ABI decoding
23pub trait AbiDecode: Sized {
24    /// Decodes the ABI encoded data
25    fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError>;
26
27    /// Decode hex encoded ABI encoded data
28    ///
29    /// Expects a hex encoded string, with optional `0x` prefix
30    fn decode_hex(data: impl AsRef<str>) -> Result<Self, AbiError> {
31        let bytes: Bytes = data.as_ref().parse()?;
32        Self::decode(bytes)
33    }
34}
35
36macro_rules! impl_abi_codec {
37    ($($name:ty),*) => {
38        $(
39            impl AbiEncode for $name {
40                fn encode(self) -> Vec<u8> {
41                    let token = self.into_token();
42                    crate::abi::encode(&[token]).into()
43                }
44            }
45            impl AbiDecode for $name {
46                fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError> {
47                    let tokens = crate::abi::decode(
48                        &[Self::param_type()], bytes.as_ref()
49                    )?;
50                    Ok(<Self as Detokenize>::from_tokens(tokens)?)
51                }
52            }
53        )*
54    };
55}
56
57impl_abi_codec!(
58    Vec<u8>,
59    Bytes,
60    bytes::Bytes,
61    Address,
62    bool,
63    String,
64    H256,
65    U128,
66    U256,
67    I256,
68    Uint8,
69    u8,
70    u16,
71    u32,
72    u64,
73    u128,
74    i8,
75    i16,
76    i32,
77    i64,
78    i128
79);
80
81impl<'a> AbiEncode for &'a str {
82    fn encode(self) -> Vec<u8> {
83        self.to_string().encode()
84    }
85}
86
87impl<T: TokenizableItem + Clone, const N: usize> AbiEncode for [T; N] {
88    fn encode(self) -> Vec<u8> {
89        let token = self.into_token();
90        crate::abi::encode(&[token])
91    }
92}
93
94impl<const N: usize> AbiEncode for [u8; N] {
95    fn encode(self) -> Vec<u8> {
96        let token = self.into_token();
97        crate::abi::encode(&[token])
98    }
99}
100
101impl<const N: usize> AbiDecode for [u8; N] {
102    fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError> {
103        let tokens = crate::abi::decode(&[Self::param_type()], bytes.as_ref())?;
104        Ok(<Self as Detokenize>::from_tokens(tokens)?)
105    }
106}
107
108impl<T, const N: usize> AbiDecode for [T; N]
109where
110    T: TokenizableItem + AbiArrayType + Clone,
111{
112    fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError> {
113        let tokens = crate::abi::decode(&[Self::param_type()], bytes.as_ref())?;
114        Ok(<Self as Detokenize>::from_tokens(tokens)?)
115    }
116}
117
118impl<T: TokenizableItem + AbiArrayType> AbiEncode for Vec<T> {
119    fn encode(self) -> Vec<u8> {
120        let token = self.into_token();
121        crate::abi::encode(&[token])
122    }
123}
124
125impl<T: TokenizableItem + AbiArrayType> AbiDecode for Vec<T> {
126    fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError> {
127        let tokens = crate::abi::decode(&[Self::param_type()], bytes.as_ref())?;
128        Ok(<Self as Detokenize>::from_tokens(tokens)?)
129    }
130}
131
132macro_rules! impl_abi_codec_tuple {
133    ($( $ty: ident),+) => {
134        impl<$($ty, )+> AbiEncode for ($($ty,)+) where
135            $(
136                $ty: Tokenizable,
137            )+
138        {
139            fn encode(self) -> Vec<u8> {
140                crate::abi::encode(&self.into_tokens()).into()
141            }
142        }
143
144        impl<$($ty, )+> AbiDecode for ($($ty,)+) where
145            $(
146                $ty: AbiType +  Tokenizable,
147            )+ {
148                fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError> {
149                    if let crate::abi::ParamType::Tuple(params) = <Self as AbiType>::param_type() {
150                      let tokens = crate::abi::decode(&params, bytes.as_ref())?;
151                      Ok(<Self as Tokenizable>::from_token(Token::Tuple(tokens))?)
152                    } else {
153                        Err(
154                            crate::abi::InvalidOutputType("Expected tuple".to_string()).into()
155                        )
156                    }
157                }
158        }
159    }
160}
161
162impl_abi_codec_tuple!(A);
163impl_abi_codec_tuple!(A, B);
164impl_abi_codec_tuple!(A, B, C);
165impl_abi_codec_tuple!(A, B, C, D);
166impl_abi_codec_tuple!(A, B, C, D, E);
167impl_abi_codec_tuple!(A, B, C, D, E, F);
168impl_abi_codec_tuple!(A, B, C, D, E, F, G);
169impl_abi_codec_tuple!(A, B, C, D, E, F, G, H);
170impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I);
171impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J);
172impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K);
173impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
174impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
175impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
176impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
177impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
178impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
179impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
180impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
181impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
182impl_abi_codec_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187    use rand::{
188        distributions::{Alphanumeric, Distribution, Standard},
189        random, thread_rng, Rng,
190    };
191    use std::fmt::Debug;
192
193    fn assert_codec<T>(val: T)
194    where
195        T: AbiDecode + AbiEncode + Clone + PartialEq + Debug,
196    {
197        let encoded = val.clone().encode();
198        assert_eq!(val, T::decode(encoded).unwrap());
199    }
200
201    macro_rules! roundtrip_alloc {
202        ($val:expr) => {
203            assert_codec($val);
204            assert_codec(($val, $val));
205            assert_codec(std::iter::repeat_with(|| $val).take(10).collect::<Vec<_>>());
206        };
207    }
208
209    macro_rules! roundtrip_all {
210        ($val:expr) => {
211            roundtrip_alloc!($val);
212            assert_codec([$val; 10]);
213        };
214    }
215
216    fn test_codec_rng<T>()
217    where
218        Standard: Distribution<T>,
219        T: AbiDecode + AbiEncode + Copy + PartialEq + Debug + AbiArrayType + TokenizableItem,
220    {
221        roundtrip_all!(random::<T>());
222    }
223
224    #[test]
225    fn address_codec() {
226        test_codec_rng::<Address>();
227    }
228
229    #[test]
230    fn uint_codec() {
231        test_codec_rng::<u16>();
232        test_codec_rng::<u32>();
233        test_codec_rng::<u64>();
234        test_codec_rng::<u128>();
235
236        test_codec_rng::<i8>();
237        test_codec_rng::<i16>();
238        test_codec_rng::<i32>();
239        test_codec_rng::<i64>();
240        test_codec_rng::<i128>();
241    }
242
243    #[test]
244    fn u8_codec() {
245        assert_codec(random::<u8>());
246        assert_codec((random::<u8>(), random::<u8>()));
247        assert_codec(std::iter::repeat_with(random::<u8>).take(10).collect::<Vec<_>>());
248        assert_codec([random::<u8>(); 10]);
249    }
250
251    #[test]
252    fn string_codec() {
253        roundtrip_alloc! { thread_rng()
254        .sample_iter(&Alphanumeric)
255        .take(30)
256        .map(char::from)
257        .collect::<String>()
258        };
259    }
260
261    #[test]
262    fn bytes_codec() {
263        let bytes: Bytes = std::iter::repeat_with(random::<u8>).take(10).collect::<Vec<_>>().into();
264        let v = vec![bytes];
265        assert_codec(v);
266    }
267
268    #[test]
269    fn tuple_array() {
270        let nested: Vec<[u8; 4]> = vec![[0, 0, 0, 1]];
271        assert_codec(nested.clone());
272        let tuple: Vec<(Address, u8, Vec<[u8; 4]>)> = vec![(Address::random(), 0, nested)];
273        assert_codec(tuple);
274    }
275
276    #[test]
277    fn str_encoding() {
278        let value = "str value";
279        let encoded = value.encode();
280        assert_eq!(value, String::decode(encoded).unwrap());
281    }
282
283    #[test]
284    fn should_decode_array_of_fixed_uint8() {
285        // uint8[8]
286        let tokens = vec![Token::FixedArray(vec![
287            Token::Uint(1.into()),
288            Token::Uint(2.into()),
289            Token::Uint(3.into()),
290            Token::Uint(4.into()),
291            Token::Uint(5.into()),
292            Token::Uint(6.into()),
293            Token::Uint(7.into()),
294            Token::Uint(8.into()),
295        ])];
296        let data: [Uint8; 8] = Detokenize::from_tokens(tokens).unwrap();
297        assert_eq!(data[0], 1);
298        assert_eq!(data[1], 2);
299        assert_eq!(data[2], 3);
300        assert_eq!(data[7], 8);
301    }
302}