From efbbd34a941f7cb3e2d15e1ff6207573bbc32ea3 Mon Sep 17 00:00:00 2001 From: Felipe Rosa Date: Fri, 11 Mar 2022 16:04:32 -0300 Subject: [PATCH] Implement Serialize for Abi --- src/abi.rs | 77 ++++++++++++++++++++++++- src/params.rs | 157 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 204 insertions(+), 30 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 1243ebe..0a43ec3 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, Error, Result}; use ethereum_types::H256; -use serde::{de::Visitor, Deserialize}; +use serde::{de::Visitor, Deserialize, Serialize}; use crate::{params::Param, DecodedParams, Event, Value}; @@ -102,6 +102,72 @@ impl std::str::FromStr for Abi { } } +impl Serialize for Abi { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut entries = vec![]; + + if let Some(c) = &self.constructor { + entries.push(AbiEntry { + type_: String::from("constructor"), + name: None, + inputs: Some(c.inputs.clone()), + outputs: None, + state_mutability: Some(StateMutability::NonPayable), + anonymous: None, + }); + } + + for f in &self.functions { + entries.push(AbiEntry { + type_: String::from("function"), + name: Some(f.name.clone()), + inputs: Some(f.inputs.clone()), + outputs: Some(f.outputs.clone()), + state_mutability: Some(f.state_mutability), + anonymous: None, + }); + } + + for e in &self.events { + entries.push(AbiEntry { + type_: String::from("event"), + name: Some(e.name.clone()), + inputs: Some(e.inputs.clone()), + outputs: None, + state_mutability: None, + anonymous: Some(e.anonymous), + }); + } + + if self.has_receive { + entries.push(AbiEntry { + type_: String::from("receive"), + name: None, + inputs: None, + outputs: None, + state_mutability: Some(StateMutability::Payable), + anonymous: None, + }); + } + + if self.has_fallback { + entries.push(AbiEntry { + type_: String::from("fallback"), + name: None, + inputs: None, + outputs: None, + state_mutability: Some(StateMutability::Payable), + anonymous: None, + }); + } + + entries.serialize(serializer) + } +} + impl<'de> Deserialize<'de> for Abi { fn deserialize(deserializer: D) -> Result where @@ -181,7 +247,7 @@ impl Function { } /// Available state mutability values for functions and constructors. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum StateMutability { /// Specified to not read the blockchain state. @@ -194,15 +260,20 @@ pub enum StateMutability { Payable, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct AbiEntry { #[serde(rename = "type")] type_: String, + #[serde(skip_serializing_if = "Option::is_none")] name: Option, + #[serde(skip_serializing_if = "Option::is_none")] inputs: Option>, + #[serde(skip_serializing_if = "Option::is_none")] outputs: Option>, + #[serde(skip_serializing_if = "Option::is_none")] state_mutability: Option, + #[serde(skip_serializing_if = "Option::is_none")] anonymous: Option, } diff --git a/src/params.rs b/src/params.rs index 2d7fc03..f066ddd 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,4 +1,4 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::{collections::HashMap, rc::Rc}; use crate::{types::Type, Value}; @@ -80,6 +80,52 @@ pub struct Param { pub indexed: Option, } +impl Param { + fn build_param_entry(&self) -> ParamEntry { + let tuple_params = match &self.type_ { + Type::Tuple(params) => Some(params.clone()), + Type::Array(ty) | Type::FixedArray(ty, _) => { + if let Type::Tuple(params) = ty.as_ref() { + Some(params.clone()) + } else { + None + } + } + _ => None, + }; + + let components = tuple_params.map(|params| { + params + .iter() + .map(|(name, ty)| { + Param { + name: name.clone(), + type_: ty.clone(), + indexed: None, + } + .build_param_entry() + }) + .collect() + }); + + ParamEntry { + name: self.name.clone(), + type_: param_type_string(&self.type_), + indexed: self.indexed, + components, + } + } +} + +impl Serialize for Param { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.build_param_entry().serialize(serializer) + } +} + impl<'a> Deserialize<'a> for Param { fn deserialize(deserializer: D) -> Result where @@ -98,12 +144,23 @@ impl<'a> Deserialize<'a> for Param { } } -#[derive(Debug, Clone, Deserialize)] +fn param_type_string(ty: &Type) -> String { + match ty { + Type::Tuple(_) => String::from("tuple"), + Type::Array(ty) => format!("{}[]", param_type_string(ty)), + Type::FixedArray(ty, size) => format!("{}[{}]", param_type_string(ty), size), + _ => format!("{}", ty), + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] struct ParamEntry { pub name: String, #[serde(rename = "type")] pub type_: String, + #[serde(skip_serializing_if = "Option::is_none")] pub indexed: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub components: Option>, } @@ -290,19 +347,20 @@ fn check_fixed_bytes_size(i: &usize) -> bool { #[cfg(test)] mod test { - use serde_json::json; - use super::*; + use pretty_assertions::assert_eq; + use serde_json::json; + #[test] - fn deserialize_uint() { + fn serde_uint() { for i in (8..=256).step_by(8) { let v = json!({ "name": "a", "type": format!("uint{}", i), }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -312,18 +370,22 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } } #[test] - fn deserialize_int() { + fn serde_int() { for i in (8..=256).step_by(8) { let v = json!({ "name": "a", "type": format!("int{}", i), }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -333,17 +395,21 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } } #[test] - fn deserialize_address() { + fn serde_address() { let v = json!({ "name": "a", "type": "address", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -353,16 +419,20 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_bool() { + fn serde_bool() { let v = json!({ "name": "a", "type": "bool", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -372,16 +442,20 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_string() { + fn serde_string() { let v = json!({ "name": "a", "type": "string", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -391,17 +465,21 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_bytes() { + fn serde_bytes() { for i in 1..=32 { let v = json!({ "name": "a", "type": format!("bytes{}", i), }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -411,6 +489,10 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } let v = json!({ @@ -418,7 +500,7 @@ mod test { "type": "bytes", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -428,15 +510,19 @@ mod test { indexed: None } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_array() { + fn serde_array() { let v = json!({ "name": "a", "type": "uint256[]", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -446,15 +532,19 @@ mod test { indexed: None, } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_nested_array() { + fn serde_nested_array() { let v = json!({ "name": "a", "type": "address[][]", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -464,15 +554,19 @@ mod test { indexed: None, } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_mixed_array() { + fn serde_mixed_array() { let v = json!({ "name": "a", "type": "string[2][]", }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -487,7 +581,8 @@ mod test { "name": "a", "type": "string[][3]", }); - let param: Param = serde_json::from_value(v).unwrap(); + + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -497,10 +592,14 @@ mod test { indexed: None, } ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } #[test] - fn deserialize_tuple() { + fn serde_tuple() { let v = json!({ "name": "s", "type": "tuple", @@ -530,7 +629,7 @@ mod test { ] }); - let param: Param = serde_json::from_value(v).unwrap(); + let param: Param = serde_json::from_value(v.clone()).expect("param deserialized"); assert_eq!( param, @@ -549,6 +648,10 @@ mod test { ]), indexed: None, } - ) + ); + + let param_json = serde_json::to_value(param.clone()).expect("param serialized"); + + assert_eq!(v, param_json); } }