multiversx_sc_meta_lib/abi_json/
contract_abi_json.rs1use super::*;
2use multiversx_sc::abi::*;
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6#[derive(Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct ContractAbiJson {
9 #[serde(default)]
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub build_info: Option<BuildInfoAbiJson>,
12
13 #[serde(default)]
14 #[serde(skip_serializing_if = "Vec::is_empty")]
15 pub docs: Vec<String>,
16
17 pub name: String,
18
19 #[serde(default)]
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub constructor: Option<ConstructorAbiJson>,
22
23 #[serde(default)]
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub upgrade_constructor: Option<ConstructorAbiJson>,
26
27 #[serde(default)]
28 pub endpoints: Vec<EndpointAbiJson>,
29
30 #[serde(default)]
31 #[serde(skip_serializing_if = "Vec::is_empty")]
32 pub promises_callback_names: Vec<String>,
33
34 #[serde(default)]
35 #[serde(skip_serializing_if = "Vec::is_empty")]
36 pub events: Vec<EventAbiJson>,
37
38 #[serde(default)]
39 pub esdt_attributes: Vec<EsdtAttributeJson>,
40
41 #[serde(default)]
42 pub has_callback: bool,
43
44 #[serde(default)]
45 pub types: BTreeMap<String, TypeDescriptionJson>,
46}
47
48impl From<ContractAbiJson> for ContractAbi {
49 fn from(abi_json: ContractAbiJson) -> Self {
50 ContractAbi {
51 build_info: abi_json
52 .build_info
53 .map(BuildInfoAbi::from)
54 .unwrap_or_default(),
55 docs: abi_json.docs,
56 name: abi_json.name,
57 constructors: abi_json
58 .constructor
59 .map(|c| vec![EndpointAbi::from(&c)])
60 .unwrap_or_default(),
61 upgrade_constructors: abi_json
62 .upgrade_constructor
63 .map(|c| vec![EndpointAbi::from(&c)])
64 .unwrap_or_default(),
65 endpoints: abi_json
66 .endpoints
67 .into_iter()
68 .map(EndpointAbi::from)
69 .collect(),
70 promise_callbacks: abi_json
71 .promises_callback_names
72 .into_iter()
73 .map(|name| EndpointAbi {
74 name,
75 ..Default::default()
76 })
77 .collect(),
78 events: abi_json.events.into_iter().map(EventAbi::from).collect(),
79 esdt_attributes: abi_json
80 .esdt_attributes
81 .into_iter()
82 .map(EsdtAttributeAbi::from)
83 .collect(),
84 has_callback: abi_json.has_callback,
85 type_descriptions: convert_json_to_type_descriptions(abi_json.types),
86 }
87 }
88}
89
90impl From<&ContractAbi> for ContractAbiJson {
91 fn from(abi: &ContractAbi) -> Self {
92 ContractAbiJson {
93 build_info: Some(BuildInfoAbiJson::from(&abi.build_info)),
94 docs: abi.docs.iter().map(|d| d.to_string()).collect(),
95 name: abi.name.to_string(),
96 constructor: abi.constructors.first().map(ConstructorAbiJson::from),
97 upgrade_constructor: abi
98 .upgrade_constructors
99 .first()
100 .map(ConstructorAbiJson::from),
101 endpoints: abi.endpoints.iter().map(EndpointAbiJson::from).collect(),
102 promises_callback_names: abi
103 .promise_callbacks
104 .iter()
105 .map(|endpoint| endpoint.name.to_string())
106 .collect(),
107 events: abi.events.iter().map(EventAbiJson::from).collect(),
108 has_callback: abi.has_callback,
109 types: convert_type_descriptions_to_json(&abi.type_descriptions),
110 esdt_attributes: abi
111 .esdt_attributes
112 .iter()
113 .map(EsdtAttributeJson::from)
114 .collect(),
115 }
116 }
117}
118
119pub fn convert_type_descriptions_to_json(
120 type_descriptions: &TypeDescriptionContainerImpl,
121) -> BTreeMap<String, TypeDescriptionJson> {
122 let mut types = BTreeMap::new();
123 for (type_names, type_description) in type_descriptions.0.iter() {
124 if type_description.contents.is_specified() {
125 types.insert(
126 type_names.abi.clone(),
127 TypeDescriptionJson::from(type_description),
128 );
129 }
130 }
131 types
132}
133
134pub fn convert_json_to_type_descriptions(
135 types: BTreeMap<String, TypeDescriptionJson>,
136) -> TypeDescriptionContainerImpl {
137 let mut type_descriptions = TypeDescriptionContainerImpl::new();
138 for (type_name, type_description) in types.into_iter() {
139 type_descriptions.insert(
140 TypeNames::from_abi(type_name),
141 TypeDescription::from(&type_description),
142 );
143 }
144 type_descriptions
145}
146
147pub fn empty_type_description_container() -> TypeDescriptionContainerImpl {
148 TypeDescriptionContainerImpl::new()
149}
150
151pub fn serialize_abi_to_json(abi_json: &ContractAbiJson) -> String {
152 let buf = Vec::new();
153 let formatter = serde_json::ser::PrettyFormatter::with_indent(b" ");
154 let mut ser = serde_json::Serializer::with_formatter(buf, formatter);
155 abi_json.serialize(&mut ser).unwrap();
156 let mut serialized = String::from_utf8(ser.into_inner()).unwrap();
157 serialized.push('\n');
158 serialized
159}
160
161pub fn deserialize_abi_from_json(input: &str) -> Result<ContractAbiJson, String> {
162 serde_json::from_str(input).map_err(|err| err.to_string())
163}
164
165#[cfg(test)]
166mod tests {
167 const MINIMAL_ABI_JSON: &str = r#"{
168 "name": "Minimal"
169 }"#;
170
171 #[test]
172 fn decode_minimal_contract_abi() {
173 super::deserialize_abi_from_json(MINIMAL_ABI_JSON).unwrap();
174 }
175}