starknet_devnet_types/
serde_helpers.rs1pub mod rpc_sierra_contract_class_to_sierra_contract_class {
2 use serde::{Deserialize, Deserializer};
3
4 pub fn deserialize_to_sierra_contract_class<'de, D>(
5 deserializer: D,
6 ) -> Result<cairo_lang_starknet_classes::contract_class::ContractClass, D::Error>
7 where
8 D: Deserializer<'de>,
9 {
10 let mut json_obj = serde_json::Value::deserialize(deserializer)?;
11 if let Some(serde_json::Value::String(abi_string)) = json_obj.get("abi") {
15 if !abi_string.is_empty() {
16 let arr: serde_json::Value =
17 serde_json::from_str(abi_string).map_err(serde::de::Error::custom)?;
18
19 json_obj
20 .as_object_mut()
21 .ok_or(serde::de::Error::custom("Expected to be an object"))?
22 .insert("abi".to_string(), arr);
23 } else {
24 json_obj
25 .as_object_mut()
26 .ok_or(serde::de::Error::custom("Expected to be an object"))?
27 .remove("abi");
28 }
29 };
30
31 serde_json::from_value(json_obj).map_err(serde::de::Error::custom)
32 }
33
34 #[cfg(test)]
35 mod tests {
36 use serde::Deserialize;
37
38 use crate::serde_helpers::rpc_sierra_contract_class_to_sierra_contract_class::deserialize_to_sierra_contract_class;
39
40 #[test]
41 fn correct_deserialization_from_sierra_contract_class_with_abi_field_as_string() {
42 #[derive(Deserialize)]
43 struct TestDeserialization(
44 #[allow(unused)]
45 #[serde(deserialize_with = "deserialize_to_sierra_contract_class")]
46 cairo_lang_starknet_classes::contract_class::ContractClass,
47 );
48
49 let path = concat!(
50 env!("CARGO_MANIFEST_DIR"),
51 "/test_data/sierra_contract_class_with_abi_as_string.json"
52 );
53
54 let json_str = std::fs::read_to_string(path).unwrap();
55
56 serde_json::from_str::<TestDeserialization>(&json_str).unwrap();
57 }
58 }
59}
60pub mod hex_string {
61 use serde::{Deserialize, Deserializer, Serializer};
62 use starknet_rs_core::types::Felt;
63
64 use crate::contract_address::ContractAddress;
65 use crate::felt::felt_from_prefixed_hex;
66 use crate::patricia_key::PatriciaKey;
67
68 pub fn deserialize_to_prefixed_patricia_key<'de, D>(
69 deserializer: D,
70 ) -> Result<PatriciaKey, D::Error>
71 where
72 D: Deserializer<'de>,
73 {
74 let felt = deserialize_prefixed_hex_string_to_felt(deserializer)?;
75 PatriciaKey::new(felt).map_err(serde::de::Error::custom)
76 }
77
78 pub fn deserialize_to_prefixed_contract_address<'de, D>(
79 deserializer: D,
80 ) -> Result<ContractAddress, D::Error>
81 where
82 D: Deserializer<'de>,
83 {
84 let felt = deserialize_prefixed_hex_string_to_felt(deserializer)?;
85 ContractAddress::new(felt).map_err(serde::de::Error::custom)
86 }
87
88 pub fn serialize_patricia_key_to_prefixed_hex<S>(
89 patricia_key: &PatriciaKey,
90 s: S,
91 ) -> Result<S::Ok, S::Error>
92 where
93 S: Serializer,
94 {
95 s.serialize_str(&patricia_key.to_felt().to_hex_string())
96 }
97
98 pub fn serialize_contract_address_to_prefixed_hex<S>(
99 contract_address: &ContractAddress,
100 s: S,
101 ) -> Result<S::Ok, S::Error>
102 where
103 S: Serializer,
104 {
105 serialize_patricia_key_to_prefixed_hex(&contract_address.0, s)
106 }
107
108 pub fn deserialize_prefixed_hex_string_to_felt<'de, D>(
109 deserializer: D,
110 ) -> Result<Felt, D::Error>
111 where
112 D: Deserializer<'de>,
113 {
114 let buf = String::deserialize(deserializer)?;
115
116 felt_from_prefixed_hex(&buf).map_err(serde::de::Error::custom)
117 }
118
119 #[cfg(test)]
120 mod tests {
121 use serde::{Deserialize, Serialize};
122 use starknet_rs_core::types::Felt;
123
124 use crate::contract_address::ContractAddress;
125 use crate::felt::felt_from_prefixed_hex;
126 use crate::patricia_key::PatriciaKey;
127 use crate::serde_helpers::hex_string::{
128 deserialize_to_prefixed_contract_address, deserialize_to_prefixed_patricia_key,
129 serialize_contract_address_to_prefixed_hex,
130 };
131
132 #[test]
133 fn deserialization_of_prefixed_hex_patricia_key_should_be_successful() {
134 #[derive(Deserialize)]
135 struct TestDeserialization {
136 #[serde(deserialize_with = "deserialize_to_prefixed_patricia_key")]
137 data: PatriciaKey,
138 }
139
140 let json_str =
141 r#"{"data": "0x800000000000000000000000000000000000000000000000000000000000000"}"#;
142 let data = serde_json::from_str::<TestDeserialization>(json_str).unwrap();
143 assert!(
144 data.data.to_felt()
145 == felt_from_prefixed_hex(
146 "0x800000000000000000000000000000000000000000000000000000000000000"
147 )
148 .unwrap()
149 )
150 }
151
152 #[test]
153 fn deserialization_of_prefixed_hex_patricia_key_should_return_error() {
154 #[derive(Deserialize)]
155 struct TestDeserialization {
156 #[allow(unused)]
157 #[serde(deserialize_with = "deserialize_to_prefixed_patricia_key")]
158 data: PatriciaKey,
159 }
160
161 let json_str =
162 r#"{"data": "0x800000000000000000000000000000000000000000000000000000000000001"}"#;
163 assert!(serde_json::from_str::<TestDeserialization>(json_str).is_err())
164 }
165
166 #[test]
167 fn deserialization_of_prefixed_hex_contract_address_should_return_error() {
168 #[derive(Deserialize)]
169 struct TestDeserialization {
170 #[allow(unused)]
171 #[serde(deserialize_with = "deserialize_to_prefixed_contract_address")]
172 data: ContractAddress,
173 }
174
175 let json_str =
176 r#"{"data": "0x800000000000000000000000000000000000000000000000000000000000001"}"#;
177 assert!(serde_json::from_str::<TestDeserialization>(json_str).is_err())
178 }
179
180 #[test]
181 fn serialization_of_prefixed_hex_contract_address_should_be_correct() {
182 #[derive(Serialize)]
183 struct TestSerialization(
184 #[serde(serialize_with = "serialize_contract_address_to_prefixed_hex")]
185 ContractAddress,
186 );
187
188 let data = TestSerialization(ContractAddress::new(Felt::ONE).unwrap());
189
190 assert_eq!(serde_json::to_string(&data).unwrap(), r#""0x1""#);
191 }
192 }
193}
194
195pub mod dec_string {
196 use std::str::FromStr;
197
198 use bigdecimal::BigDecimal;
199 use num_bigint::BigUint;
200 use serde::Deserialize;
201
202 pub fn deserialize_biguint<'de, D>(deserializer: D) -> Result<BigUint, D::Error>
203 where
204 D: serde::Deserializer<'de>,
205 {
206 let number = serde_json::Number::deserialize(deserializer)?;
207 let big_decimal =
209 BigDecimal::from_str(number.as_str()).map_err(serde::de::Error::custom)?;
210
211 BigUint::from_str(&big_decimal.with_scale(0).to_string()).map_err(serde::de::Error::custom)
213 }
214
215 #[cfg(test)]
216 mod tests {
217 use num_bigint::BigUint;
218 use serde::Deserialize;
219
220 use crate::serde_helpers::dec_string::deserialize_biguint;
221
222 #[test]
223 fn deserialization_biguint() {
224 #[derive(Deserialize)]
225 struct TestDeserializationStruct {
226 #[serde(deserialize_with = "deserialize_biguint")]
227 value: BigUint,
228 }
229
230 for (json_str, expected) in [
231 (
232 r#"{"value": 3618502788666131106986593281521497120414687020801267626233049500247285301248}"#,
233 BigUint::from(1_u8) << 251,
234 ),
235 (r#"{"value": 1000000000000000000000000000000}"#, BigUint::from(10_u8).pow(30)),
236 (
237 r#"{"value": 1000000000000000000000000000001}"#,
238 BigUint::from(10_u8).pow(30) + BigUint::from(1_u8),
239 ),
240 (r#"{"value": 1e30}"#, BigUint::from(10_u8).pow(30)),
241 (r#"{"value": 1.23e1}"#, BigUint::from(12_u8)),
242 (r#"{"value": 1.29e1}"#, BigUint::from(12_u8)),
243 (r#"{"value": 100.0}"#, BigUint::from(100_u8)),
244 ] {
245 match serde_json::from_str::<TestDeserializationStruct>(json_str) {
246 Ok(data) => assert_eq!(data.value, expected),
247 Err(e) => panic!("Unexpected response {e} for parsing: {json_str}"),
248 }
249 }
250 }
251 }
252}
253
254pub mod base_64_gzipped_json_string {
255 use base64::Engine;
256 use flate2::Compression;
257 use flate2::write::GzEncoder;
258 use serde::{Deserialize, Deserializer, Serializer};
259 use serde_json::Value;
260 use starknet_rs_core::serde::byte_array::base64 as base64Sir;
261 use starknet_rs_core::types::contract::legacy::LegacyProgram;
262
263 pub fn deserialize_to_serde_json_value_with_keys_ordered_in_alphabetical_order<'de, D>(
264 deserializer: D,
265 ) -> Result<serde_json::Value, D::Error>
266 where
267 D: Deserializer<'de>,
268 {
269 let buf = String::deserialize(deserializer)?;
270 if buf.is_empty() {
271 return Ok(serde_json::Value::Null);
272 }
273
274 let bytes = base64::engine::general_purpose::STANDARD
276 .decode(buf)
277 .map_err(|_| serde::de::Error::custom("program: Unable to decode base64 string"))?;
278
279 let decoder = flate2::read::GzDecoder::new(bytes.as_slice());
280 let starknet_program: LegacyProgram = serde_json::from_reader(decoder)
281 .map_err(|_| serde::de::Error::custom("program: Unable to decode gzipped bytes"))?;
282
283 serde_json::to_value(starknet_program)
284 .map_err(|_| serde::de::Error::custom("program: Unable to parse to JSON"))
285 }
286
287 pub fn serialize_program_to_base64<S>(program: &Value, serializer: S) -> Result<S::Ok, S::Error>
288 where
289 S: Serializer,
290 {
291 let mut buffer = Vec::new();
292 let encoder = GzEncoder::new(&mut buffer, Compression::best());
293 serde_json::to_writer(encoder, program)
294 .map_err(|_| serde::ser::Error::custom("program: Unable to encode program"))?;
295
296 base64Sir::serialize(&buffer, serializer)
297 }
298
299 #[cfg(test)]
300 mod tests {
301 use std::fs::File;
302
303 use serde::Deserialize;
304 use serde_json::json;
305
306 use crate::serde_helpers::base_64_gzipped_json_string::deserialize_to_serde_json_value_with_keys_ordered_in_alphabetical_order;
307 use crate::utils::test_utils::CAIRO_0_RPC_CONTRACT_PATH;
308
309 #[test]
310 fn deserialize_successfully_starknet_api_program() {
311 let json_value: serde_json::Value =
312 serde_json::from_reader(File::open(CAIRO_0_RPC_CONTRACT_PATH).unwrap()).unwrap();
313
314 #[derive(Deserialize)]
315 struct TestDeserialization {
316 #[allow(unused)]
317 #[serde(
318 deserialize_with = "deserialize_to_serde_json_value_with_keys_ordered_in_alphabetical_order"
319 )]
320 program: serde_json::Value,
321 }
322
323 serde_json::from_str::<TestDeserialization>(
324 &serde_json::to_string(&json!({ "program": json_value["program"]})).unwrap(),
325 )
326 .unwrap();
327 }
328 }
329}