1use std::string::ToString;
12
13use crate::{
14 decode, encode, signature::short_signature, Bytes, Error, Param, ParamType, Result, StateMutability, Token,
15};
16use serde::Deserialize;
17
18#[derive(Debug, Clone, PartialEq, Deserialize)]
20pub struct Function {
21 pub name: String,
23 pub inputs: Vec<Param>,
25 pub outputs: Vec<Param>,
27 #[deprecated(note = "The constant attribute was removed in Solidity 0.5.0 and has been \
28 replaced with stateMutability. If parsing a JSON AST created with \
29 this version or later this value will always be false, which may be wrong.")]
30 #[serde(default)]
32 pub constant: bool,
33 #[serde(rename = "stateMutability", default)]
35 pub state_mutability: StateMutability,
36}
37
38impl Function {
39 fn input_param_types(&self) -> Vec<ParamType> {
41 self.inputs.iter().map(|p| p.kind.clone()).collect()
42 }
43
44 fn output_param_types(&self) -> Vec<ParamType> {
46 self.outputs.iter().map(|p| p.kind.clone()).collect()
47 }
48
49 pub fn encode_input(&self, tokens: &[Token]) -> Result<Bytes> {
51 let params = self.input_param_types();
52
53 if !Token::types_check(tokens, ¶ms) {
54 return Err(Error::InvalidData);
55 }
56
57 let signed = short_signature(&self.name, ¶ms).to_vec();
58 let encoded = encode(tokens);
59 Ok(signed.into_iter().chain(encoded.into_iter()).collect())
60 }
61
62 pub fn decode_output(&self, data: &[u8]) -> Result<Vec<Token>> {
64 decode(&self.output_param_types(), &data)
65 }
66
67 pub fn decode_input(&self, data: &[u8]) -> Result<Vec<Token>> {
69 decode(&self.input_param_types(), &data)
70 }
71
72 pub fn signature(&self) -> String {
80 let inputs = self.inputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
81
82 let outputs = self.outputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
83
84 match (inputs.len(), outputs.len()) {
85 (_, 0) => format!("{}({})", self.name, inputs),
86 (_, _) => format!("{}({}):({})", self.name, inputs, outputs),
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use crate::{Function, Param, ParamType, StateMutability, Token};
94 use hex_literal::hex;
95
96 #[test]
97 fn test_function_encode_call() {
98 let func = Function {
99 name: "baz".to_owned(),
100 inputs: vec![
101 Param { name: "a".to_owned(), kind: ParamType::Uint(32) },
102 Param { name: "b".to_owned(), kind: ParamType::Bool },
103 ],
104 outputs: vec![],
105 constant: false,
106 state_mutability: StateMutability::Payable,
107 };
108
109 let mut uint = [0u8; 32];
110 uint[31] = 69;
111 let encoded = func.encode_input(&[Token::Uint(uint.into()), Token::Bool(true)]).unwrap();
112 let expected = hex!("cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001").to_vec();
113 assert_eq!(encoded, expected);
114 }
115}