polymesh_api_client/
basic_types.rs

1use codec::{Compact, CompactAs, Decode, Encode};
2
3use core::{fmt, str::FromStr};
4
5#[cfg(feature = "serde")]
6use serde::{de::DeserializeOwned, ser, Deserialize, Serialize};
7
8#[cfg(all(feature = "std", feature = "type_info"))]
9use scale_info::TypeInfo;
10
11#[cfg(not(feature = "std"))]
12use alloc::{format, string::String};
13use sp_core::crypto::Ss58Codec;
14use sp_std::prelude::*;
15
16// Re-export some basic crates.
17pub use frame_metadata;
18
19pub use sp_core;
20
21pub use sp_core::hashing;
22
23pub use sp_weights;
24
25pub use sp_runtime::MultiSignature;
26
27// Re-impl `OldWeight`
28#[derive(
29  Clone, Copy, Debug, Encode, Decode, CompactAs, Default, PartialEq, Eq, PartialOrd, Ord,
30)]
31#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[cfg_attr(feature = "serde", serde(transparent))]
34pub struct OldWeight(pub u64);
35
36// Re-impl `per_things` to support serde
37pub mod per_things {
38  use super::*;
39
40  #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
41  #[cfg_attr(feature = "std", derive(Hash))]
42  #[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
43  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
44  pub struct Perbill(pub u32);
45
46  impl CompactAs for Perbill {
47    type As = u32;
48
49    fn encode_as(&self) -> &Self::As {
50      &self.0
51    }
52
53    fn decode_from(v: Self::As) -> Result<Self, codec::Error> {
54      Ok(Self(v))
55    }
56  }
57
58  impl From<Compact<Self>> for Perbill {
59    fn from(c: Compact<Self>) -> Self {
60      c.0
61    }
62  }
63
64  impl From<sp_arithmetic::per_things::Perbill> for Perbill {
65    fn from(p: sp_arithmetic::per_things::Perbill) -> Self {
66      Self(p.deconstruct())
67    }
68  }
69
70  #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
71  #[cfg_attr(feature = "std", derive(Hash))]
72  #[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
73  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74  pub struct PerU16(pub u16);
75
76  impl CompactAs for PerU16 {
77    type As = u16;
78
79    fn encode_as(&self) -> &Self::As {
80      &self.0
81    }
82
83    fn decode_from(v: Self::As) -> Result<Self, codec::Error> {
84      Ok(Self(v))
85    }
86  }
87
88  impl From<Compact<Self>> for PerU16 {
89    fn from(c: Compact<Self>) -> Self {
90      c.0
91    }
92  }
93
94  impl From<sp_arithmetic::per_things::PerU16> for PerU16 {
95    fn from(p: sp_arithmetic::per_things::PerU16) -> Self {
96      Self(p.deconstruct())
97    }
98  }
99
100  #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
101  #[cfg_attr(feature = "std", derive(Hash))]
102  #[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
103  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104  pub struct Permill(pub u32);
105
106  impl CompactAs for Permill {
107    type As = u32;
108
109    fn encode_as(&self) -> &Self::As {
110      &self.0
111    }
112
113    fn decode_from(v: Self::As) -> Result<Self, codec::Error> {
114      Ok(Self(v))
115    }
116  }
117
118  impl From<Compact<Self>> for Permill {
119    fn from(c: Compact<Self>) -> Self {
120      c.0
121    }
122  }
123
124  impl From<sp_arithmetic::per_things::Permill> for Permill {
125    fn from(p: sp_arithmetic::per_things::Permill) -> Self {
126      Self(p.deconstruct())
127    }
128  }
129
130  #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
131  #[cfg_attr(feature = "std", derive(Hash))]
132  #[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
133  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134  pub struct Percent(pub u8);
135
136  impl CompactAs for Percent {
137    type As = u8;
138
139    fn encode_as(&self) -> &Self::As {
140      &self.0
141    }
142
143    fn decode_from(v: Self::As) -> Result<Self, codec::Error> {
144      Ok(Self(v))
145    }
146  }
147
148  impl From<Compact<Self>> for Percent {
149    fn from(c: Compact<Self>) -> Self {
150      c.0
151    }
152  }
153
154  impl From<sp_arithmetic::per_things::Percent> for Percent {
155    fn from(p: sp_arithmetic::per_things::Percent) -> Self {
156      Self(p.deconstruct())
157    }
158  }
159}
160
161#[cfg(not(feature = "serde"))]
162pub trait AccountTraits: Clone + Encode + Decode + Default + FromStr {}
163
164#[cfg(not(feature = "serde"))]
165impl<T> AccountTraits for T where T: Clone + Encode + Decode + Default + FromStr {}
166
167#[cfg(feature = "serde")]
168pub trait AccountTraits:
169  Clone + Encode + Decode + Default + FromStr + ser::Serialize + DeserializeOwned
170{
171}
172
173#[cfg(feature = "serde")]
174impl<T> AccountTraits for T where
175  T: Clone + Encode + Decode + Default + FromStr + ser::Serialize + DeserializeOwned
176{
177}
178
179// Re-impl MultiAddress to support serde
180#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord)]
181#[cfg_attr(feature = "std", derive(Hash))]
182#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
183pub enum MultiAddress<AccountId: AccountTraits, AccountIndex: AccountTraits> {
184  /// It's an account ID (pubkey).
185  Id(AccountId),
186  /// It's an account index.
187  Index(#[codec(compact)] AccountIndex),
188  /// It's some arbitrary raw bytes.
189  Raw(Vec<u8>),
190  /// It's a 32 byte representation.
191  Address32([u8; 32]),
192  /// Its a 20 byte representation.
193  Address20([u8; 20]),
194}
195
196impl<AccountId: AccountTraits, AccountIndex: AccountTraits> From<&AccountId>
197  for MultiAddress<AccountId, AccountIndex>
198{
199  fn from(other: &AccountId) -> Self {
200    Self::Id(other.clone())
201  }
202}
203
204impl<AccountId: AccountTraits, AccountIndex: AccountTraits> From<AccountId>
205  for MultiAddress<AccountId, AccountIndex>
206{
207  fn from(other: AccountId) -> Self {
208    Self::Id(other)
209  }
210}
211
212impl<AccountIndex: AccountTraits> From<sp_runtime::AccountId32>
213  for MultiAddress<AccountId, AccountIndex>
214{
215  fn from(other: sp_runtime::AccountId32) -> Self {
216    Self::Id(other.into())
217  }
218}
219
220impl<AccountId: AccountTraits, AccountIndex: AccountTraits>
221  From<sp_runtime::MultiAddress<AccountId, AccountIndex>>
222  for MultiAddress<AccountId, AccountIndex>
223{
224  fn from(other: sp_runtime::MultiAddress<AccountId, AccountIndex>) -> Self {
225    match other {
226      sp_runtime::MultiAddress::Id(v) => Self::Id(v),
227      sp_runtime::MultiAddress::Index(v) => Self::Index(v),
228      sp_runtime::MultiAddress::Raw(v) => Self::Raw(v),
229      sp_runtime::MultiAddress::Address32(v) => Self::Address32(v),
230      sp_runtime::MultiAddress::Address20(v) => Self::Address20(v),
231    }
232  }
233}
234
235impl<AccountId: AccountTraits, AccountIndex: AccountTraits>
236  From<&sp_runtime::MultiAddress<AccountId, AccountIndex>>
237  for MultiAddress<AccountId, AccountIndex>
238{
239  fn from(other: &sp_runtime::MultiAddress<AccountId, AccountIndex>) -> Self {
240    Self::from(other.clone())
241  }
242}
243
244#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
245#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
246pub struct AccountId(pub [u8; 32]);
247
248impl AccountId {
249  pub fn to_hex(&self) -> String {
250    format!("0x{}", hex::encode(&self.0))
251  }
252}
253
254impl FromStr for AccountId {
255  type Err = crate::Error;
256
257  fn from_str(s: &str) -> Result<Self, Self::Err> {
258    match s.len() {
259      66 if s.starts_with("0x") => {
260        let mut id = AccountId::default();
261        hex::decode_to_slice(&s[2..], &mut id.0)?;
262        Ok(id)
263      }
264      64 => {
265        let mut id = AccountId::default();
266        hex::decode_to_slice(&s[0..], &mut id.0)?;
267        Ok(id)
268      }
269      _ => Ok(AccountId::from_ss58check(s)?),
270    }
271  }
272}
273
274#[cfg(not(feature = "serde"))]
275impl AccountId {
276  pub fn to_ss58check(&self) -> String {
277    format!("0x{}", hex::encode(&self.0))
278  }
279}
280
281impl Ss58Codec for AccountId {}
282
283impl fmt::Display for AccountId {
284  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285    write!(f, "{}", self.to_ss58check())
286  }
287}
288
289impl fmt::Debug for AccountId {
290  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291    let ss58 = self.to_ss58check();
292    let h = hex::encode(&self.0);
293    write!(f, "0x{} ({}...)", h, &ss58[0..8])
294  }
295}
296
297impl<'a> TryFrom<&'a [u8]> for AccountId {
298  type Error = ();
299
300  fn try_from(x: &'a [u8]) -> Result<Self, ()> {
301    Ok(AccountId(x.try_into().map_err(|_| ())?))
302  }
303}
304
305impl AsMut<[u8; 32]> for AccountId {
306  fn as_mut(&mut self) -> &mut [u8; 32] {
307    &mut self.0
308  }
309}
310
311impl AsMut<[u8]> for AccountId {
312  fn as_mut(&mut self) -> &mut [u8] {
313    &mut self.0[..]
314  }
315}
316
317impl AsRef<[u8; 32]> for AccountId {
318  fn as_ref(&self) -> &[u8; 32] {
319    &self.0
320  }
321}
322
323impl AsRef<[u8]> for AccountId {
324  fn as_ref(&self) -> &[u8] {
325    &self.0[..]
326  }
327}
328
329impl sp_core::ByteArray for AccountId {
330  const LEN: usize = 32;
331}
332
333impl From<[u8; 32]> for AccountId {
334  fn from(p: [u8; 32]) -> Self {
335    Self(p)
336  }
337}
338
339impl From<sp_core::sr25519::Public> for AccountId {
340  fn from(p: sp_core::sr25519::Public) -> Self {
341    p.0.into()
342  }
343}
344
345impl From<sp_core::ed25519::Public> for AccountId {
346  fn from(p: sp_core::ed25519::Public) -> Self {
347    p.0.into()
348  }
349}
350
351impl From<sp_runtime::AccountId32> for AccountId {
352  fn from(id: sp_runtime::AccountId32) -> Self {
353    Self(*id.as_ref())
354  }
355}
356
357impl From<&sp_runtime::AccountId32> for AccountId {
358  fn from(id: &sp_runtime::AccountId32) -> Self {
359    Self(*id.as_ref())
360  }
361}
362
363impl From<AccountId> for sp_runtime::AccountId32 {
364  fn from(id: AccountId) -> Self {
365    Self::new(id.0)
366  }
367}
368
369impl From<&AccountId> for sp_runtime::AccountId32 {
370  fn from(id: &AccountId) -> Self {
371    Self::new(id.0)
372  }
373}
374
375pub type GenericAddress = MultiAddress<AccountId, u32>;
376
377#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
378#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
379#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
380#[cfg_attr(
381  feature = "utoipa",
382  schema(value_type = String, format = Binary, example = "0x0600000000000000000000000000000000000000000000000000000000000000")
383)]
384pub struct IdentityId(pub [u8; 32]);
385
386impl fmt::Display for IdentityId {
387  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
388    let h = hex::encode(&self.0);
389    write!(f, "0x{}", h)
390  }
391}
392
393impl fmt::Debug for IdentityId {
394  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
395    let h = hex::encode(&self.0);
396    write!(f, "0x{}", h)
397  }
398}
399
400#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
401#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
402#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
403#[cfg_attr(
404  feature = "utoipa",
405  schema(value_type = String, format = Binary, example = "67e55044-10b1-426f-9247-bb680e5fe0c8")
406)]
407pub struct AssetId(pub [u8; 16]);
408
409impl AssetId {
410  pub fn as_uuid(&self) -> uuid::Uuid {
411    uuid::Uuid::from_bytes(self.0)
412  }
413}
414
415impl fmt::Display for AssetId {
416  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417    self.as_uuid().fmt(f)
418  }
419}
420
421impl fmt::Debug for AssetId {
422  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
423    self.as_uuid().fmt(f)
424  }
425}
426
427impl From<uuid::Uuid> for AssetId {
428  fn from(uuid: uuid::Uuid) -> Self {
429    Self(uuid.into_bytes())
430  }
431}
432
433impl FromStr for AssetId {
434  type Err = uuid::Error;
435
436  fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
437    let uuid = uuid::Uuid::parse_str(uuid_str)?;
438    Ok(uuid.into())
439  }
440}
441
442impl TryFrom<&'_ str> for AssetId {
443  type Error = uuid::Error;
444
445  fn try_from(uuid_str: &'_ str) -> Result<Self, Self::Error> {
446    let uuid = uuid::Uuid::parse_str(uuid_str)?;
447    Ok(uuid.into())
448  }
449}
450
451#[cfg(test)]
452mod tests {
453  use super::*;
454  use serde_json::json;
455
456  #[test]
457  fn account_id_deserialize() {
458    let json_hex = json!("0x788b804aeea9afcf7042c6ee45ddc2a394f4e225918e3261a9b5ed5069037d09");
459    let json_ss58 = json!("5Enm3VfZioxHVBpZgJcACv7pZPZZeYWymvrZ9cxkXhNHJWe5");
460    let expected = AccountId::from_ss58check("5Enm3VfZioxHVBpZgJcACv7pZPZZeYWymvrZ9cxkXhNHJWe5")
461      .expect("AccountId");
462
463    let decoded: AccountId = serde_json::from_str(&json_hex.to_string()).expect("decode as json");
464    assert_eq!(decoded, expected);
465    let decoded: AccountId = serde_json::from_str(&json_ss58.to_string()).expect("decode as json");
466    assert_eq!(decoded, expected);
467  }
468
469  #[test]
470  fn account_id_roundtrip() {
471    let account = AccountId::from_ss58check("5Enm3VfZioxHVBpZgJcACv7pZPZZeYWymvrZ9cxkXhNHJWe5")
472      .expect("AccountId");
473    let data = serde_json::to_string(&account).expect("encode json");
474    let decoded: AccountId = serde_json::from_str(&data).expect("decode as json");
475    assert_eq!(decoded, account);
476  }
477
478  #[test]
479  fn asset_id_roundtrip() {
480    let asset: AssetId = "67e55044-10b1-426f-9247-bb680e5fe0c8"
481      .parse()
482      .expect("AssetId");
483    let data = serde_json::to_string(&asset).expect("encode json");
484    let decoded: AssetId = serde_json::from_str(&data).expect("decode as json");
485    assert_eq!(decoded, asset);
486  }
487
488  #[test]
489  fn asset_id_display() {
490    let str_id = "67e55044-10b1-426f-9247-bb680e5fe0c8";
491    let asset: AssetId = str_id.parse().expect("AssetId");
492    let display_id = format!("{asset}");
493    assert_eq!(display_id, str_id);
494  }
495
496  #[test]
497  fn multi_address_roundtrip() {
498    let account = AccountId::from_ss58check("5Enm3VfZioxHVBpZgJcACv7pZPZZeYWymvrZ9cxkXhNHJWe5")
499      .expect("AccountId");
500    // Round-trip test MultiAddress::Id variant.
501    let address = GenericAddress::Id(account);
502    let data = serde_json::to_string(&address).expect("encode json");
503    eprintln!("MultiAddress::Id = {data}");
504    let decoded: GenericAddress = serde_json::from_str(&data).expect("decode as json");
505    assert_eq!(decoded, address);
506    // Round-trip test MultiAddress::Index variant.
507    let address = GenericAddress::Index(1234);
508    let data = serde_json::to_string(&address).expect("encode json");
509    eprintln!("MultiAddress::Index = {data}");
510    let decoded: GenericAddress = serde_json::from_str(&data).expect("decode as json");
511    assert_eq!(decoded, address);
512    // Round-trip test MultiAddress::Raw variant.
513    let address = GenericAddress::Raw(vec![0, 1, 2, 3, 4, 5]);
514    let data = serde_json::to_string(&address).expect("encode json");
515    eprintln!("MultiAddress::Raw = {data}");
516    let decoded: GenericAddress = serde_json::from_str(&data).expect("decode as json");
517    assert_eq!(decoded, address);
518    // Round-trip test MultiAddress::Address32 variant.
519    let address = GenericAddress::Address32([1; 32]);
520    let data = serde_json::to_string(&address).expect("encode json");
521    eprintln!("MultiAddress::Address32 = {data}");
522    let decoded: GenericAddress = serde_json::from_str(&data).expect("decode as json");
523    assert_eq!(decoded, address);
524    // Round-trip test MultiAddress::Address20 variant.
525    let address = GenericAddress::Address20([2; 20]);
526    let data = serde_json::to_string(&address).expect("encode json");
527    eprintln!("MultiAddress::Address20 = {data}");
528    let decoded: GenericAddress = serde_json::from_str(&data).expect("decode as json");
529    assert_eq!(decoded, address);
530  }
531}