rustabi/
function.rs

1//! Contract function call builder.
2
3use signature::short_signature;
4use {Param, Token, Result, ErrorKind, Bytes, decode, ParamType, encode};
5
6/// Contract function specification.
7#[derive(Debug, Clone, PartialEq, Deserialize)]
8pub struct Function {
9	/// Function name.
10	pub name: String,
11	/// Function input.
12	pub inputs: Vec<Param>,
13	/// Function output.
14	pub outputs: Vec<Param>,
15	/// Constant function.
16	#[serde(default)]
17	pub constant: bool,
18}
19
20impl Function {
21	/// Returns all input params of given function.
22	fn input_param_types(&self) -> Vec<ParamType> {
23		self.inputs.iter()
24			.map(|p| p.kind.clone())
25			.collect()
26	}
27
28	/// Returns all output params of given function.
29	fn output_param_types(&self) -> Vec<ParamType> {
30		self.outputs.iter()
31			.map(|p| p.kind.clone())
32			.collect()
33	}
34
35	/// Prepares ABI function call with given input params.
36	pub fn encode_input(&self, tokens: &[Token]) -> Result<Bytes> {
37		let params = self.input_param_types();
38
39		if !Token::types_check(tokens, &params) {
40			return Err(ErrorKind::InvalidData.into());
41		}
42
43		let signed = short_signature(&self.name, &params).to_vec();
44		let encoded = encode(tokens);
45		Ok(signed.into_iter().chain(encoded.into_iter()).collect())
46	}
47
48	/// Parses the ABI function output to list of tokens.
49	pub fn decode_output(&self, data: &[u8]) -> Result<Vec<Token>> {
50		decode(&self.output_param_types(), &data)
51	}
52}
53
54#[cfg(test)]
55mod tests {
56	use {Token, Param, Function, ParamType};
57
58	#[test]
59	fn test_function_encode_call() {
60		let interface = Function {
61			name: "baz".to_owned(),
62			inputs: vec![Param {
63				name: "a".to_owned(),
64				kind: ParamType::Uint(32),
65			}, Param {
66				name: "b".to_owned(),
67				kind: ParamType::Bool,
68			}],
69			outputs: vec![],
70			constant: false,
71		};
72
73		let func = Function::from(interface);
74		let mut uint = [0u8; 32];
75		uint[31] = 69;
76		let encoded = func.encode_input(&[Token::Uint(uint.into()), Token::Bool(true)]).unwrap();
77		let expected = hex!("cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001").to_vec();
78		assert_eq!(encoded, expected);
79	}
80}