ethabi_fork_ethcontract/
function.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//! Contract function call builder.
10
11use std::string::ToString;
12
13use crate::signature::short_signature;
14use crate::{decode, encode, Bytes, Error, Param, ParamType, Result, StateMutability, Token};
15use serde::Deserialize;
16
17/// Contract function specification.
18#[derive(Debug, Clone, PartialEq, Deserialize)]
19pub struct Function {
20	/// Function name.
21	pub name: String,
22	/// Function input.
23	pub inputs: Vec<Param>,
24	/// Function output.
25	pub outputs: Vec<Param>,
26	#[deprecated(note = "The constant attribute was removed in Solidity 0.5.0 and has been \
27				replaced with stateMutability. If parsing a JSON AST created with \
28				this version or later this value will always be false, which may be wrong.")]
29	/// Constant function.
30	#[serde(default)]
31	pub constant: bool,
32	/// Whether the function reads or modifies blockchain state
33	#[serde(rename = "stateMutability", default)]
34	pub state_mutability: StateMutability,
35}
36
37impl Function {
38	/// Returns all input params of given function.
39	fn input_param_types(&self) -> Vec<ParamType> {
40		self.inputs.iter().map(|p| p.kind.clone()).collect()
41	}
42
43	/// Returns all output params of given function.
44	fn output_param_types(&self) -> Vec<ParamType> {
45		self.outputs.iter().map(|p| p.kind.clone()).collect()
46	}
47
48	/// Prepares ABI function call with given input params.
49	pub fn encode_input(&self, tokens: &[Token]) -> Result<Bytes> {
50		let params = self.input_param_types();
51
52		if !Token::types_check(tokens, &params) {
53			return Err(Error::InvalidData);
54		}
55
56		let signed = short_signature(&self.name, &params).to_vec();
57		let encoded = encode(tokens);
58		Ok(signed.into_iter().chain(encoded.into_iter()).collect())
59	}
60
61	/// Parses the ABI function output to list of tokens.
62	pub fn decode_output(&self, data: &[u8]) -> Result<Vec<Token>> {
63		decode(&self.output_param_types(), &data)
64	}
65
66	/// Parses the ABI function input to a list of tokens.
67	pub fn decode_input(&self, data: &[u8]) -> Result<Vec<Token>> {
68		decode(&self.input_param_types(), &data)
69	}
70
71	/// Returns a signature that uniquely identifies this function.
72	///
73	/// Examples:
74	/// - `functionName()`
75	/// - `functionName():(uint256)`
76	/// - `functionName(bool):(uint256,string)`
77	/// - `functionName(uint256,bytes32):(string,uint256)`
78	pub fn signature(&self) -> String {
79		let inputs = self.inputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
80
81		let outputs = self.outputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
82
83		match (inputs.len(), outputs.len()) {
84			(_, 0) => format!("{}({})", self.name, inputs),
85			(_, _) => format!("{}({}):({})", self.name, inputs, outputs),
86		}
87	}
88}
89
90#[cfg(test)]
91mod tests {
92	use crate::{Function, Param, ParamType, StateMutability, Token};
93	use hex_literal::hex;
94
95	#[test]
96	fn test_function_encode_call() {
97		let func = Function {
98			name: "baz".to_owned(),
99			inputs: vec![
100				Param { name: "a".to_owned(), kind: ParamType::Uint(32) },
101				Param { name: "b".to_owned(), kind: ParamType::Bool },
102			],
103			outputs: vec![],
104			constant: false,
105			state_mutability: StateMutability::Payable,
106		};
107
108		let mut uint = [0u8; 32];
109		uint[31] = 69;
110		let encoded = func.encode_input(&[Token::Uint(uint.into()), Token::Bool(true)]).unwrap();
111		let expected = hex!("cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001").to_vec();
112		assert_eq!(encoded, expected);
113	}
114}