ethane_abi/
function.rs

1use crate::AbiParserError;
2use crate::ParameterType;
3
4/// An ABI function instance.
5///
6/// Contains the fields of a properly encoded ABI function. The function name
7/// is available as the key to the respective function in the `HashMap` of the
8/// [`crate::Abi`] parser.
9pub struct Function {
10    pub inputs: Vec<FunctionParameter>,
11    pub outputs: Vec<FunctionParameter>,
12    pub state_mutability: Option<StateMutability>,
13    pub payable: Option<bool>,
14    pub constant: Option<bool>,
15}
16
17impl Function {
18    /// Tries to parse a `.json` file into a [`Function`].
19    pub fn parse(raw_func: &serde_json::Value) -> Result<Self, AbiParserError> {
20        let inputs = Self::parse_parameters(&raw_func["inputs"])?;
21        let outputs = Self::parse_parameters(&raw_func["outputs"])?;
22        Ok(Self {
23            inputs,
24            outputs,
25            state_mutability: StateMutability::parse(raw_func),
26            payable: raw_func["payable"].as_bool(), // as_bool() automatically returns an Option<bool>
27            constant: raw_func["constant"].as_bool(), // as_bool() automatically returns an Option<bool>
28        })
29    }
30
31    /// Tries to parse a `.json` string  into an array of ABI function
32    /// parameters.
33    ///
34    /// If the ABI file is properly formatted, both the function inputs and
35    /// outputs can be parsed using this function.
36    fn parse_parameters(
37        raw_func: &serde_json::Value,
38    ) -> Result<Vec<FunctionParameter>, AbiParserError> {
39        match raw_func {
40            serde_json::Value::Array(parameters) => {
41                let mut result = Vec::new();
42                for parameter in parameters {
43                    let p_type = parameter["type"].as_str().ok_or_else(|| {
44                        AbiParserError::MissingData("Missing parameter type".to_owned())
45                    })?;
46                    let p_name = parameter["name"].as_str().ok_or_else(|| {
47                        AbiParserError::MissingData("Missing parameter name".to_owned())
48                    })?;
49                    let parameter_type = ParameterType::parse(p_type)?;
50                    result.push(FunctionParameter {
51                        name: p_name.to_owned(),
52                        parameter_type,
53                    });
54                }
55                Ok(result)
56            }
57            _ => Err(AbiParserError::InvalidAbiEncoding(
58                "Function parameters are not given as an array".to_owned(),
59            )),
60        }
61    }
62}
63
64/// ABI function parameter type.
65///
66/// Contains the name of the parameter (which can be an empty string) and the
67/// type of the parameter as a [`ParameterType`].
68pub struct FunctionParameter {
69    pub name: String,
70    pub parameter_type: ParameterType,
71}
72
73/// Possible variants of an ABI function's respective state mutability flags.
74#[derive(Copy, Clone, Debug, PartialEq)]
75pub enum StateMutability {
76    Pure,
77    View,
78    NonPayable,
79    Payable,
80}
81
82impl StateMutability {
83    /// Attempts to parse a `.json` string into an optional [`StateMutability`]
84    /// flag.
85    pub fn parse(raw_func: &serde_json::Value) -> Option<Self> {
86        match raw_func["stateMutability"].as_str() {
87            Some("pure") => Some(StateMutability::Pure),
88            Some("view") => Some(StateMutability::View),
89            Some("nonpayable") => Some(StateMutability::NonPayable),
90            Some("payable") => Some(StateMutability::Payable),
91            _ => None,
92        }
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use super::*;
99    use crate::ParameterType;
100
101    #[test]
102    fn parse_function() {
103        let json: serde_json::Value = serde_json::from_str(
104            r#"{
105            "constant": true,
106            "name": "stuff",
107            "inputs": [
108                {
109                    "name": "_spender",
110                    "type": "address"
111                },
112                {
113                    "name": "",
114                    "type": "bytes64"
115                }
116            ],
117            "outputs": [],
118            "payable": false,
119            "type": "function",
120            "stateMutability": "view"
121        }"#,
122        )
123        .unwrap();
124
125        let function = Function::parse(&json).unwrap();
126        assert_eq!(function.inputs.len(), 2);
127        assert_eq!(function.inputs[0].parameter_type, ParameterType::Address);
128        assert_eq!(function.inputs[0].name, "_spender");
129        assert_eq!(
130            function.inputs[1].parameter_type,
131            ParameterType::FixedBytes(64)
132        );
133        assert!(function.inputs[1].name.is_empty());
134        assert!(function.outputs.is_empty());
135        assert_eq!(function.constant, Some(true));
136        assert_eq!(function.payable, Some(false));
137        assert_eq!(function.state_mutability, Some(StateMutability::View));
138    }
139}