ethabi_next/token/
token.rs

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