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