common_primitives/
utils.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4/// Mainnet Genesis Hash 0x4a587bf17a404e3572747add7aab7bbe56e805a5479c6c436f07f36fcc8d3ae1
5pub const MAINNET_GENESIS_HASH: &[u8] = &[
6	74u8, 88, 123, 241, 122, 64, 78, 53, 114, 116, 122, 221, 122, 171, 123, 190, 86, 232, 5, 165,
7	71, 156, 108, 67, 111, 7, 243, 111, 204, 141, 58, 225,
8];
9
10/// Frequency Testnet on Paseo Genesis Hash 0x203c6838fc78ea3660a2f298a58d859519c72a5efdc0f194abd6f0d5ce1838e0
11pub const TESTNET_ON_PASEO_GENESIS_HASH: &[u8] = &[
12	32, 60, 104, 56, 252, 120, 234, 54, 96, 162, 242, 152, 165, 141, 133, 149, 25, 199, 42, 94,
13	253, 192, 241, 148, 171, 214, 240, 213, 206, 24, 56, 224,
14];
15
16/// Frequency Testnet on Westend Genesis Hash 0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e
17pub const TESTNET_ON_WESTEND_GENESIS_HASH: &[u8] = &[
18	225, 67, 242, 56, 3, 172, 80, 232, 246, 248, 230, 38, 149, 209, 206, 158, 78, 29, 104, 170, 54,
19	193, 205, 44, 253, 21, 52, 2, 19, 243, 66, 62,
20];
21
22/// An enum that shows the detected chain type
23#[derive(Debug, Clone, PartialEq)]
24pub enum DetectedChainType {
25	/// An unknown chain, it can be a local or development chain
26	Unknown,
27	/// Frequency Mainnet
28	FrequencyMainNet,
29	/// Frequency Paseo Testnet
30	FrequencyPaseoTestNet,
31	/// Frequency Westend Testnet
32	FrequencyWestendTestNet,
33}
34
35/// Finds the chain type by genesis hash
36pub fn get_chain_type_by_genesis_hash(genesis_hash: &[u8]) -> DetectedChainType {
37	match genesis_hash {
38		MAINNET_GENESIS_HASH => DetectedChainType::FrequencyMainNet,
39		TESTNET_ON_PASEO_GENESIS_HASH => DetectedChainType::FrequencyPaseoTestNet,
40		TESTNET_ON_WESTEND_GENESIS_HASH => DetectedChainType::FrequencyWestendTestNet,
41		_ => DetectedChainType::Unknown,
42	}
43}
44
45/// Generic function for converting any unsigned integer to a 32-byte array compatible with ETH abi
46pub fn to_abi_compatible_number<T: Into<u128>>(value: T) -> [u8; 32] {
47	let value_u128: u128 = value.into();
48	let bytes = value_u128.to_be_bytes();
49	let start_idx = 32 - bytes.len();
50	let mut result = [0u8; 32];
51	result[start_idx..].copy_from_slice(&bytes);
52	result
53}
54
55/// Handle serializing and deserializing from `Vec<u8>` to hexadecimal
56#[cfg(feature = "std")]
57pub mod as_hex {
58	use serde::{Deserializer, Serializer};
59
60	/// Serializes a `Vec<u8>` into a hexadecimal string
61	pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
62	where
63		S: Serializer,
64	{
65		impl_serde::serialize::serialize(bytes.as_slice(), serializer)
66	}
67
68	/// Deserializes a hexadecimal string into a `Vec<u8>`
69	pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
70		impl_serde::serialize::deserialize(deserializer)
71	}
72}
73
74/// Handle serializing and deserializing from `Option<Vec<u8>>` to hexadecimal
75#[cfg(feature = "std")]
76pub mod as_hex_option {
77	use serde::{Deserializer, Serializer};
78
79	/// Serializes a `Vec<u8>` into a hexadecimal string
80	pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
81	where
82		S: Serializer,
83	{
84		match bytes {
85			Some(bytes) => impl_serde::serialize::serialize(bytes.as_slice(), serializer),
86			None => serializer.serialize_none(),
87		}
88	}
89
90	/// Deserializes a hexadecimal string into a `Vec<u8>`
91	pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
92	where
93		D: Deserializer<'de>,
94	{
95		impl_serde::serialize::deserialize(deserializer).map(Some)
96	}
97}
98/// Handle serializing and deserializing from `Vec<u8>` to a UTF-8 string
99#[cfg(feature = "std")]
100pub mod as_string {
101	use super::*;
102	use serde::{ser::Error, Deserialize, Deserializer, Serialize, Serializer};
103
104	/// Serializes a `Vec<u8>` into a UTF-8 string
105	pub fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
106		std::str::from_utf8(bytes)
107			.map_err(|e| S::Error::custom(format!("Debug buffer contains invalid UTF8: {e:?}")))?
108			.serialize(serializer)
109	}
110
111	/// Serializes a UTF-8 string into a `Vec<u8>`
112	pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
113		Ok(String::deserialize(deserializer)?.into_bytes())
114	}
115}
116
117/// Handle serializing and deserializing from `Option<Vec<u8>>` to a UTF-8 string
118#[cfg(feature = "std")]
119pub mod as_string_option {
120	use super::*;
121	use serde::{ser::Error, Deserialize, Deserializer, Serialize, Serializer};
122
123	/// Serializes a `Option<Vec<u8>>` into a UTF-8 string if Ok()
124	pub fn serialize<S: Serializer>(
125		bytes: &Option<Vec<u8>>,
126		serializer: S,
127	) -> Result<S::Ok, S::Error> {
128		match bytes {
129			Some(bytes) => std::str::from_utf8(bytes)
130				.map_err(|e| {
131					S::Error::custom(format!("Debug buffer contains invalid UTF8: {e:?}"))
132				})?
133				.serialize(serializer),
134			None => serializer.serialize_none(),
135		}
136	}
137
138	/// Deserializes a UTF-8 string into a `Option<Vec<u8>>`
139	pub fn deserialize<'de, D: Deserializer<'de>>(
140		deserializer: D,
141	) -> Result<Option<Vec<u8>>, D::Error> {
142		let bytes = String::deserialize(deserializer)?.into_bytes();
143		Ok(match bytes.len() {
144			0 => None,
145			_ => Some(bytes),
146		})
147	}
148}
149
150const PREFIX: &str = "<Bytes>";
151const POSTFIX: &str = "</Bytes>";
152
153/// Wraps `PREFIX` and `POSTFIX` around a `Vec<u8>`
154/// Returns `PREFIX` ++ `data` ++ `POSTFIX`
155pub fn wrap_binary_data(data: Vec<u8>) -> Vec<u8> {
156	let mut encapsuled = PREFIX.as_bytes().to_vec();
157	encapsuled.append(&mut data.clone());
158	encapsuled.append(&mut POSTFIX.as_bytes().to_vec());
159	encapsuled
160}
161
162#[cfg(test)]
163mod tests {
164	use super::*;
165	use impl_serde::serialize::from_hex;
166	use parity_scale_codec::{Decode, Encode};
167	use scale_info::TypeInfo;
168	use serde::{Deserialize, Serialize};
169	use sp_core::U256;
170
171	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
172	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
173	struct TestAsHex {
174		#[cfg_attr(feature = "std", serde(with = "as_hex",))]
175		pub data: Vec<u8>,
176	}
177
178	#[test]
179	fn as_hex_can_serialize() {
180		let test_data = TestAsHex { data: vec![1, 2, 3, 4] };
181		let result = serde_json::to_string(&test_data);
182		assert!(result.is_ok());
183		assert_eq!("{\"data\":\"0x01020304\"}", result.unwrap());
184	}
185
186	#[test]
187	fn as_hex_can_deserialize() {
188		let result: Result<TestAsHex, serde_json::Error> =
189			serde_json::from_str("{\"data\":\"0x01020304\"}");
190		assert!(result.is_ok());
191		assert_eq!(vec![1, 2, 3, 4], result.unwrap().data);
192	}
193
194	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
195	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
196	struct TestAsHexOption {
197		#[cfg_attr(
198			feature = "std",
199			serde(with = "as_hex_option", skip_serializing_if = "Option::is_none", default)
200		)]
201		pub data: Option<Vec<u8>>,
202	}
203
204	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
205	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
206	struct TestAsHexOptionNull {
207		#[cfg_attr(feature = "std", serde(with = "as_hex_option", default))]
208		pub data: Option<Vec<u8>>,
209	}
210
211	#[test]
212	fn as_hex_option_can_serialize() {
213		let test_data = TestAsHexOption { data: Some(vec![1, 2, 3, 4]) };
214		let result = serde_json::to_string(&test_data);
215		assert!(result.is_ok());
216		assert_eq!("{\"data\":\"0x01020304\"}", result.unwrap());
217	}
218
219	#[test]
220	fn as_hex_option_can_deserialize() {
221		let result: Result<TestAsHexOption, serde_json::Error> =
222			serde_json::from_str("{\"data\":\"0x01020304\"}");
223		assert!(result.is_ok());
224		assert_eq!(Some(vec![1, 2, 3, 4]), result.unwrap().data);
225	}
226
227	#[test]
228	fn as_hex_option_can_serialize_nothing_with_skip() {
229		let test_data = TestAsHexOption { data: None };
230		let result = serde_json::to_string(&test_data);
231		assert!(result.is_ok());
232		assert_eq!("{}", result.unwrap());
233	}
234
235	#[test]
236	fn as_hex_option_can_serialize_nothing_as_null() {
237		let test_data = TestAsHexOptionNull { data: None };
238		let result = serde_json::to_string(&test_data);
239		assert!(result.is_ok());
240		assert_eq!("{\"data\":null}", result.unwrap());
241	}
242
243	#[test]
244	fn as_hex_option_can_deserialize_nothing() {
245		let result: Result<TestAsHexOption, serde_json::Error> = serde_json::from_str("{}");
246		assert!(result.is_ok());
247		assert_eq!(None, result.unwrap().data);
248	}
249
250	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
251	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
252	struct TestAsString {
253		#[cfg_attr(feature = "std", serde(with = "as_string"))]
254		pub data: Vec<u8>,
255	}
256
257	#[test]
258	fn as_string_can_serialize() {
259		let test_data = TestAsString {
260			data: vec![
261				0xe8, 0x95, 0x99, 0x49, 0xdd, 0x9d, 0xcd, 0x99, 0xe0, 0xbc, 0x8d, 0x4c, 0xd0, 0xbc,
262			],
263		};
264		let result = serde_json::to_string(&test_data);
265		assert!(result.is_ok());
266		assert_eq!("{\"data\":\"蕙Iݝ͙།Lм\"}", result.unwrap());
267	}
268
269	#[test]
270	fn as_string_can_deserialize() {
271		let result: Result<TestAsString, serde_json::Error> =
272			serde_json::from_str("{\"data\":\"蕙Iݝ͙།Lм\"}");
273		assert!(result.is_ok());
274		assert_eq!(
275			vec![
276				0xe8, 0x95, 0x99, 0x49, 0xdd, 0x9d, 0xcd, 0x99, 0xe0, 0xbc, 0x8d, 0x4c, 0xd0, 0xbc
277			],
278			result.unwrap().data
279		);
280	}
281
282	#[test]
283	fn as_string_errors_for_bad_utf8_vec() {
284		let test_data = TestAsString { data: vec![0xc3, 0x28] };
285		let result = serde_json::to_string(&test_data);
286		assert!(result.is_err());
287	}
288
289	#[test]
290	fn as_string_errors_for_bad_utf8_str() {
291		let result: Result<TestAsString, serde_json::Error> =
292			serde_json::from_str("{\"data\":\"\\xa0\\xa1\"}");
293		assert!(result.is_err());
294	}
295
296	#[test]
297	fn get_chain_type_by_genesis_hash_with_mainnet_genesis_should_get_mainnet() {
298		// arrange
299		let known_genesis =
300			from_hex("4a587bf17a404e3572747add7aab7bbe56e805a5479c6c436f07f36fcc8d3ae1").unwrap();
301
302		// act
303		let detected = get_chain_type_by_genesis_hash(&known_genesis);
304
305		// assert
306		assert_eq!(detected, DetectedChainType::FrequencyMainNet);
307	}
308
309	#[test]
310	fn get_chain_type_by_genesis_hash_with_paseo_genesis_should_get_paseo() {
311		// arrange
312		let known_genesis =
313			from_hex("203c6838fc78ea3660a2f298a58d859519c72a5efdc0f194abd6f0d5ce1838e0").unwrap();
314
315		// act
316		let detected = get_chain_type_by_genesis_hash(&known_genesis);
317
318		// assert
319		assert_eq!(detected, DetectedChainType::FrequencyPaseoTestNet);
320	}
321
322	#[test]
323	fn abi_compatible_number_should_work_with_different_types() {
324		// For u8
325		let u8_val: u8 = 42;
326		let coded_u8_val = to_abi_compatible_number(u8_val);
327		let u8_val: U256 = u8_val.into();
328		assert_eq!(
329			coded_u8_val.to_vec(),
330			sp_core::bytes::from_hex(&format!("0x{:064x}", u8_val)).unwrap()
331		);
332
333		// For u16
334		let u16_val: u16 = 12345;
335		let coded_u16_val = to_abi_compatible_number(u16_val);
336		let u16_val: U256 = u16_val.into();
337		assert_eq!(
338			coded_u16_val.to_vec(),
339			sp_core::bytes::from_hex(&format!("0x{:064x}", u16_val)).unwrap()
340		);
341
342		// For u32
343		let u32_val: u32 = 305419896;
344		let coded_u32_val = to_abi_compatible_number(u32_val);
345		let u32_val: U256 = u32_val.into();
346		assert_eq!(
347			coded_u32_val.to_vec(),
348			sp_core::bytes::from_hex(&format!("0x{:064x}", u32_val)).unwrap()
349		);
350
351		// For u64
352		let u64_val: u64 = 1234567890123456789;
353		let coded_u64_val = to_abi_compatible_number(u64_val);
354		let u64_val: U256 = u64_val.into();
355		assert_eq!(
356			coded_u64_val.to_vec(),
357			sp_core::bytes::from_hex(&format!("0x{:064x}", u64_val)).unwrap()
358		);
359
360		// For u128
361		let u128_val: u128 = 340282366920938463463374607431768211455; // Max u128 value
362		let coded_u128_val = to_abi_compatible_number(u128_val);
363		let u128_val: U256 = u128_val.into();
364		assert_eq!(
365			coded_u128_val.to_vec(),
366			sp_core::bytes::from_hex(&format!("0x{:064x}", u128_val)).unwrap()
367		);
368	}
369
370	#[test]
371	fn get_chain_type_by_genesis_hash_with_westend_genesis_should_get_westend() {
372		// arrange
373		let known_genesis =
374			from_hex("e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e").unwrap();
375
376		// act
377		let detected = get_chain_type_by_genesis_hash(&known_genesis);
378
379		// assert
380		assert_eq!(detected, DetectedChainType::FrequencyWestendTestNet);
381	}
382}