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
8pub trait AbiEncode {
10 fn encode(self) -> Vec<u8>;
12
13 fn encode_hex(self) -> String
15 where
16 Self: Sized,
17 {
18 hex::encode_prefixed(self.encode())
19 }
20}
21
22pub trait AbiDecode: Sized {
24 fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, AbiError>;
26
27 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(¶ms, 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 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}