ethabi_decode/
token.rs

1// Copyright 2015-2020 Parity Technologies
2// Copyright 2020 Snowfork
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0 <LICENSE or
7// http://www.apache.org/licenses/LICENSE-2.0>. This file may not be 
8// copied, modified, or distributed except according to those terms.
9
10//! Ethereum ABI params.
11use crate::{Address, ParamKind, U256};
12
13use crate::std::Vec;
14
15/// Ethereum ABI params.
16#[derive(Debug, PartialEq, Clone)]
17pub enum Token {
18	/// Address.
19	///
20	/// solidity name: address
21	/// Encoded to left padded [0u8; 32].
22	Address(Address),
23	/// Vector of bytes with known size.
24	///
25	/// solidity name eg.: bytes8, bytes32, bytes64, bytes1024
26	/// Encoded to right padded [0u8; ((N + 31) / 32) * 32].
27	FixedBytes(Vec<u8>),
28	/// Vector of bytes of unknown size.
29	///
30	/// solidity name: bytes
31	/// Encoded in two parts.
32	/// Init part: offset of 'closing part`.
33	/// Closing part: encoded length followed by encoded right padded bytes.
34	Bytes(Vec<u8>),
35	/// Signed integer.
36	///
37	/// solidity name: int
38	Int(U256),
39	/// Unisnged integer.
40	///
41	/// solidity name: uint
42	Uint(U256),
43	/// Boolean value.
44	///
45	/// solidity name: bool
46	/// Encoded as left padded [0u8; 32], where last bit represents boolean value.
47	Bool(bool),
48	/// String.
49	///
50	/// solidity name: string
51	/// Encoded in the same way as bytes. Must be utf8 compliant.
52	String(Vec<u8>),
53	/// Array with known size.
54	///
55	/// solidity name eg.: int[3], bool[3], address[][8]
56	/// Encoding of array is equal to encoding of consecutive elements of array.
57	FixedArray(Vec<Token>),
58	/// Array of params with unknown size.
59	///
60	/// solidity name eg. int[], bool[], address[5][]
61	Array(Vec<Token>),
62	/// Tuple of params of variable types.
63	///
64	/// solidity name: tuple
65	Tuple(Vec<Token>),
66}
67
68impl Token {
69	/// Check whether the type of the token matches the given parameter type.
70	///
71	/// Numeric types (`Int` and `Uint`) type check if the size of the token
72	/// type is of greater or equal size than the provided parameter type.
73	pub fn type_check(&self, param_type: &ParamKind) -> bool {
74		match *self {
75			Token::Address(_) => *param_type == ParamKind::Address,
76			Token::Bytes(_) => *param_type == ParamKind::Bytes,
77			Token::Int(_) => {
78				if let ParamKind::Int(_) = *param_type {
79					true
80				} else {
81					false
82				}
83			}
84			Token::Uint(_) => {
85				if let ParamKind::Uint(_) = *param_type {
86					true
87				} else {
88					false
89				}
90			}
91			Token::Bool(_) => *param_type == ParamKind::Bool,
92			Token::String(_) => *param_type == ParamKind::String,
93			Token::FixedBytes(ref bytes) => {
94				if let ParamKind::FixedBytes(size) = *param_type {
95					size >= bytes.len()
96				} else {
97					false
98				}
99			}
100			Token::Array(ref tokens) => {
101				if let ParamKind::Array(ref param_type) = *param_type {
102					tokens.iter().all(|t| t.type_check(param_type))
103				} else {
104					false
105				}
106			}
107			Token::FixedArray(ref tokens) => {
108				if let ParamKind::FixedArray(ref param_type, size) = *param_type {
109					size == tokens.len() && tokens.iter().all(|t| t.type_check(param_type))
110				} else {
111					false
112				}
113			}
114			Token::Tuple(ref tokens) => {
115				if let ParamKind::Tuple(ref param_type) = *param_type {
116					tokens.iter().enumerate().all(|(i, t)| t.type_check(&param_type[i]))
117				} else {
118					false
119				}
120			}
121		}
122	}
123
124	/// Converts token to...
125	pub fn to_address(self) -> Option<Address> {
126		match self {
127			Token::Address(address) => Some(address),
128			_ => None,
129		}
130	}
131
132	/// Converts token to...
133	pub fn to_fixed_bytes(self) -> Option<Vec<u8>> {
134		match self {
135			Token::FixedBytes(bytes) => Some(bytes),
136			_ => None,
137		}
138	}
139
140	/// Converts token to...
141	pub fn to_bytes(self) -> Option<Vec<u8>> {
142		match self {
143			Token::Bytes(bytes) => Some(bytes),
144			_ => None,
145		}
146	}
147
148	/// Converts token to...
149	pub fn to_int(self) -> Option<U256> {
150		match self {
151			Token::Int(int) => Some(int),
152			_ => None,
153		}
154	}
155
156	/// Converts token to...
157	pub fn to_uint(self) -> Option<U256> {
158		match self {
159			Token::Uint(uint) => Some(uint),
160			_ => None,
161		}
162	}
163
164	/// Converts token to...
165	pub fn to_bool(self) -> Option<bool> {
166		match self {
167			Token::Bool(b) => Some(b),
168			_ => None,
169		}
170	}
171
172	/// Converts token to...
173	pub fn to_string(self) -> Option<Vec<u8>> {
174		match self {
175			Token::String(s) => Some(s),
176			_ => None,
177		}
178	}
179
180	/// Converts token to...
181	pub fn to_fixed_array(self) -> Option<Vec<Token>> {
182		match self {
183			Token::FixedArray(arr) => Some(arr),
184			_ => None,
185		}
186	}
187
188	/// Converts token to...
189	pub fn to_array(self) -> Option<Vec<Token>> {
190		match self {
191			Token::Array(arr) => Some(arr),
192			_ => None,
193		}
194	}
195
196	/// Check if all the types of the tokens match the given parameter types.
197	pub fn types_check(tokens: &[Token], param_types: &[ParamKind]) -> bool {
198		param_types.len() == tokens.len() && {
199			param_types.iter().zip(tokens).all(|(param_type, token)| token.type_check(param_type))
200		}
201	}
202
203	/// Check if the token is a dynamic type resulting in prefixed encoding
204	pub fn is_dynamic(&self) -> bool {
205		match self {
206			Token::Bytes(_) | Token::String(_) | Token::Array(_) => true,
207			Token::FixedArray(tokens) => tokens.iter().any(|token| token.is_dynamic()),
208			Token::Tuple(tokens) => tokens.iter().any(|token| token.is_dynamic()),
209			_ => false,
210		}
211	}
212}
213
214#[cfg(test)]
215mod tests {
216	use crate::{ParamKind, Token};
217
218	#[test]
219	fn test_type_check() {
220		fn assert_type_check(tokens: Vec<Token>, param_types: Vec<ParamKind>) {
221			assert!(Token::types_check(&tokens, &param_types))
222		}
223
224		fn assert_not_type_check(tokens: Vec<Token>, param_types: Vec<ParamKind>) {
225			assert!(!Token::types_check(&tokens, &param_types))
226		}
227
228		assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamKind::Uint(256), ParamKind::Bool]);
229		assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamKind::Uint(32), ParamKind::Bool]);
230
231		assert_not_type_check(vec![Token::Uint(0.into())], vec![ParamKind::Uint(32), ParamKind::Bool]);
232		assert_not_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamKind::Uint(32)]);
233		assert_not_type_check(
234			vec![Token::Bool(false), Token::Uint(0.into())],
235			vec![ParamKind::Uint(32), ParamKind::Bool],
236		);
237
238		assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamKind::FixedBytes(4)]);
239		assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0])], vec![ParamKind::FixedBytes(4)]);
240		assert_not_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamKind::FixedBytes(3)]);
241
242		assert_type_check(
243			vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])],
244			vec![ParamKind::Array(Box::new(ParamKind::Bool))],
245		);
246		assert_not_type_check(
247			vec![Token::Array(vec![Token::Bool(false), Token::Uint(0.into())])],
248			vec![ParamKind::Array(Box::new(ParamKind::Bool))],
249		);
250		assert_not_type_check(
251			vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])],
252			vec![ParamKind::Array(Box::new(ParamKind::Address))],
253		);
254
255		assert_type_check(
256			vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
257			vec![ParamKind::FixedArray(Box::new(ParamKind::Bool), 2)],
258		);
259		assert_not_type_check(
260			vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
261			vec![ParamKind::FixedArray(Box::new(ParamKind::Bool), 3)],
262		);
263		assert_not_type_check(
264			vec![Token::FixedArray(vec![Token::Bool(false), Token::Uint(0.into())])],
265			vec![ParamKind::FixedArray(Box::new(ParamKind::Bool), 2)],
266		);
267		assert_not_type_check(
268			vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
269			vec![ParamKind::FixedArray(Box::new(ParamKind::Address), 2)],
270		);
271	}
272
273	#[test]
274	fn test_is_dynamic() {
275		assert_eq!(Token::Address("0000000000000000000000000000000000000000".parse().unwrap()).is_dynamic(), false);
276		assert_eq!(Token::Bytes(vec![0, 0, 0, 0]).is_dynamic(), true);
277		assert_eq!(Token::FixedBytes(vec![0, 0, 0, 0]).is_dynamic(), false);
278		assert_eq!(Token::Uint(0.into()).is_dynamic(), false);
279		assert_eq!(Token::Int(0.into()).is_dynamic(), false);
280		assert_eq!(Token::Bool(false).is_dynamic(), false);
281		assert_eq!(Token::String("".into()).is_dynamic(), true);
282		assert_eq!(Token::Array(vec![Token::Bool(false)]).is_dynamic(), true);
283		assert_eq!(Token::FixedArray(vec![Token::Uint(0.into())]).is_dynamic(), false);
284		assert_eq!(Token::FixedArray(vec![Token::String("".into())]).is_dynamic(), true);
285		assert_eq!(Token::FixedArray(vec![Token::Array(vec![Token::Bool(false)])]).is_dynamic(), true);
286	}
287}