polymesh_api_codegen/
generate.rs

1#![allow(deprecated)]
2use std::collections::{BTreeMap, BTreeSet};
3
4use heck::ToSnakeCase;
5
6use indexmap::IndexMap;
7
8use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote, TokenStreamExt};
10
11use codec::Decode;
12use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
13
14fn segments_ident(segments: &[String], import_types: bool) -> TokenStream {
15  let idents: Vec<_> = segments.into_iter().map(|s| format_ident!("{s}")).collect();
16  if import_types && idents.len() > 1 {
17    quote! {
18      types::#(#idents)::*
19    }
20  } else {
21    quote! {
22      #(#idents)::*
23    }
24  }
25}
26
27struct ModuleCode {
28  name: String,
29  sub_modules: BTreeMap<String, ModuleCode>,
30  types: BTreeMap<String, TokenStream>,
31}
32
33impl ModuleCode {
34  fn new(name: String) -> Self {
35    Self {
36      name,
37      sub_modules: BTreeMap::new(),
38      types: BTreeMap::new(),
39    }
40  }
41
42  fn add_type(&mut self, segments: &[String], ident: String, code: TokenStream) {
43    if let Some((mod_name, segments)) = segments.split_first() {
44      let entry = self.sub_modules.entry(mod_name.into());
45      let sub = entry.or_insert_with(|| ModuleCode::new(mod_name.into()));
46      sub.add_type(segments, ident, code);
47    } else if self.name.len() > 0 {
48      self.types.insert(ident, code);
49    }
50  }
51
52  fn gen(self) -> TokenStream {
53    let mut code = TokenStream::new();
54    for (name, sub) in self.sub_modules {
55      let ident = format_ident!("{name}");
56      let sub_code = sub.gen();
57      code.append_all(quote! {
58        pub mod #ident {
59          use super::*;
60          #sub_code
61        }
62      });
63    }
64    for (_, ty_code) in self.types {
65      code.append_all(ty_code);
66    }
67    code
68  }
69}
70
71#[cfg(feature = "v14")]
72mod v14 {
73  use super::*;
74  use frame_metadata::v14::{
75    RuntimeMetadataV14, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
76  };
77  use scale_info::{form::PortableForm, Field, Path, Type, TypeDef, Variant};
78
79  #[derive(Default)]
80  struct TypeParameters {
81    names: IndexMap<u32, String>,
82    used: BTreeSet<String>,
83    need_bounds: BTreeMap<u32, BTreeMap<String, TokenStream>>,
84  }
85
86  impl TypeParameters {
87    fn new(ty: &Type<PortableForm>) -> Self {
88      let mut names = IndexMap::new();
89
90      let ty_params = ty.type_params();
91      if ty_params.len() > 0 {
92        for p in ty_params {
93          if let Some(p_ty) = p.ty() {
94            let name = p.name();
95            names.insert(p_ty.id(), name.into());
96          }
97        }
98      }
99
100      Self {
101        names,
102        used: Default::default(),
103        need_bounds: Default::default(),
104      }
105    }
106
107    fn add_param_bounds(&mut self, id: u32, bound_name: &str, type_bound: TokenStream) -> bool {
108      if self.names.contains_key(&id) {
109        let bounds = self.need_bounds.entry(id).or_default();
110        bounds.insert(bound_name.to_string(), type_bound);
111        true
112      } else {
113        false
114      }
115    }
116
117    fn get_param(&mut self, id: u32) -> Option<TokenStream> {
118      self.names.get(&id).map(|name| {
119        self.used.insert(name.to_string());
120        let name = format_ident!("{name}");
121        quote! { #name }
122      })
123    }
124
125    fn get_type_params(&self) -> TokenStream {
126      if self.names.len() > 0 {
127        let params = self.names.iter().map(|(id, name)| {
128          let ident = format_ident!("{name}");
129          if let Some(with_bounds) = self.need_bounds.get(&id) {
130            let bounds: Vec<_> = with_bounds.values().collect();
131            quote!(#ident: #(#bounds) + *)
132          } else {
133            quote!(#ident)
134          }
135        });
136        quote!(<#(#params),*>)
137      } else {
138        TokenStream::new()
139      }
140    }
141
142    fn get_unused_params(&self) -> Option<TokenStream> {
143      if self.used.len() < self.names.len() {
144        let params = self
145          .names
146          .values()
147          .filter(|name| !self.used.contains(*name))
148          .map(|name| {
149            let ident = format_ident!("{name}");
150            quote!(#ident)
151          })
152          .collect::<Vec<_>>();
153        // Return a tuple type with the unused params.
154        if params.len() > 1 {
155          Some(quote! { core::marker::PhantomData<(#(#params),*)> })
156        } else {
157          Some(quote! { core::marker::PhantomData<#(#params),*> })
158        }
159      } else {
160        None
161      }
162    }
163  }
164
165  struct Generator {
166    md: RuntimeMetadataV14,
167    external_modules: BTreeSet<String>,
168    pallet_types: BTreeMap<u32, (String, String)>,
169    max_error_size: usize,
170    rename_types: BTreeMap<String, TokenStream>,
171    remap_namespaces: BTreeMap<String, String>,
172    ord_types: BTreeSet<String>,
173    custom_derives: BTreeMap<String, TokenStream>,
174    runtime_namespace: Vec<String>,
175    call: TokenStream,
176    event: TokenStream,
177    v2_weights: bool,
178    api_interface: TokenStream,
179  }
180
181  impl Generator {
182    fn new(md: RuntimeMetadataV14) -> Self {
183      // Detect the chain runtime path.
184      let runtime_ty = md.types.resolve(md.ty.id()).unwrap();
185      let runtime_namespace = runtime_ty.path().namespace();
186      #[cfg(feature = "ink")]
187      let api_interface = quote!(::polymesh_api_ink);
188      #[cfg(not(feature = "ink"))]
189      let api_interface = quote!(::polymesh_api_client);
190
191      let call = quote! { runtime::RuntimeCall };
192      let event = quote! { runtime::RuntimeEvent };
193      let external_modules = BTreeSet::from_iter(
194        ["sp_version", "sp_weights", "bounded_collections"]
195          .iter()
196          .map(|t| t.to_string()),
197      );
198      let rename_types = BTreeMap::from_iter(
199        [
200          (
201            "sp_core::crypto::AccountId32",
202            quote!(#api_interface::AccountId),
203          ),
204          (
205            "polymesh_primitives::identity_id::IdentityId",
206            quote!(#api_interface::IdentityId),
207          ),
208          (
209            "polymesh_primitives::asset::AssetId",
210            quote!(#api_interface::AssetId),
211          ),
212          (
213            "sp_runtime::multiaddress::MultiAddress",
214            quote!(#api_interface::MultiAddress),
215          ),
216          #[cfg(not(feature = "ink"))]
217          ("sp_runtime::generic::era::Era", quote!(#api_interface::Era)),
218          (
219            "sp_arithmetic::per_things::Perbill",
220            quote!(#api_interface::per_things::Perbill),
221          ),
222          (
223            "sp_arithmetic::per_things::Permill",
224            quote!(#api_interface::per_things::Permill),
225          ),
226          (
227            "sp_arithmetic::per_things::PerU16",
228            quote!(#api_interface::per_things::PerU16),
229          ),
230          (
231            "sp_arithmetic::per_things::Percent",
232            quote!(#api_interface::per_things::Percent),
233          ),
234          ("BTreeSet", quote!(::alloc::collections::BTreeSet)),
235          ("BTreeMap", quote!(::alloc::collections::BTreeMap)),
236          ("String", quote!(::alloc::string::String)),
237          ("Vec", quote!(::alloc::vec::Vec)),
238          (
239            "bounded_collections::bounded_btree_map::BoundedBTreeMap",
240            quote!(::alloc::collections::BTreeMap),
241          ),
242          (
243            "bounded_collections::bounded_btree_set::BoundedBTreeSet",
244            quote!(::alloc::collections::BTreeSet),
245          ),
246          (
247            "bounded_collections::bounded_vec::BoundedVec",
248            quote!(::alloc::vec::Vec),
249          ),
250          (
251            "bounded_collections::weak_bounded_vec::WeakBoundedVec",
252            quote!(::alloc::vec::Vec),
253          ),
254          (
255            "types::frame_support::storage::weak_bounded_vec::WeakBoundedVec",
256            quote!(::alloc::vec::Vec),
257          ),
258          (
259            "types::frame_support::storage::bounded_vec::BoundedVec",
260            quote!(::alloc::vec::Vec),
261          ),
262          (
263            "types::frame_system::EventRecord",
264            quote!(#api_interface::EventRecord),
265          ),
266          ("sp_weights::OldWeight", quote!(#api_interface::OldWeight)),
267          (
268            "sp_weights::Weight",
269            quote!(#api_interface::sp_weights::Weight),
270          ),
271          (
272            "sp_weights::weight_v2::Weight",
273            quote!(#api_interface::sp_weights::Weight),
274          ),
275        ]
276        .into_iter()
277        .map(|(name, code)| (name.to_string(), code)),
278      );
279      let remap_namespaces = BTreeMap::from_iter(
280        [
281          (
282            "polymesh_common_utilities::traits::balances",
283            "pallet_balances",
284          ),
285          (
286            "polymesh_common_utilities::traits::checkpoint",
287            "polymesh_primitives::checkpoint",
288          ),
289          (
290            "polymesh_common_utilities::traits::identity",
291            "polymesh_primitives::identity",
292          ),
293          (
294            "polymesh_common_utilities::traits::group",
295            "polymesh_primitives::group",
296          ),
297        ]
298        .into_iter()
299        .map(|(old, new)| (old.to_string(), new.to_string())),
300      );
301      let ink_derives = quote! {
302        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
303      };
304      let ink_enum_derives = quote! {
305        #[derive(Copy)]
306        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
307      };
308      let ink_extra_derives = quote! {
309        #[derive(Default)]
310        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
311      };
312      let ink_id_derives = quote! {
313        #[derive(Copy, Default)]
314        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
315      };
316      let custom_derives = BTreeMap::from_iter(
317        [
318          // Asset types.
319          ("AssetName", &ink_extra_derives),
320          ("AssetType", &ink_enum_derives),
321          ("NonFungibleType", &ink_enum_derives),
322          ("AssetIdentifier", &ink_enum_derives),
323          ("CustomAssetTypeId", &ink_id_derives),
324          ("FundingRoundName", &ink_extra_derives),
325          ("Ticker", &ink_id_derives),
326          ("AssetId", &ink_id_derives),
327          ("AssetID", &ink_id_derives),
328          // Settlement leg and portfolio move types.
329          ("Fund", &ink_derives),
330          ("FundDescription", &ink_derives),
331          ("FungibleToken", &ink_derives),
332          ("NFTId", &ink_id_derives),
333          ("NFTs", &ink_derives),
334          ("Leg", &ink_derives),
335          ("FungibleLeg", &ink_derives),
336          ("NonFungibleLeg", &ink_derives),
337          ("OffChainLeg", &ink_derives),
338          // Portfolio
339          ("PortfolioId", &ink_enum_derives),
340          ("PortfolioKind", &ink_enum_derives),
341          ("PortfolioNumber", &ink_id_derives),
342          ("MovePortfolioItem", &ink_derives),
343          ("Memo", &ink_derives),
344          // Settlement types.
345          ("VenueId", &ink_id_derives),
346          ("VenueDetails", &ink_extra_derives),
347          ("VenueType", &ink_enum_derives),
348          ("LegId", &ink_id_derives),
349          ("InstructionId", &ink_id_derives),
350          ("AffirmationStatus", &ink_enum_derives),
351          ("InstructionStatus", &ink_enum_derives),
352          ("LegStatus", &ink_enum_derives),
353          ("SettlementType", &ink_enum_derives),
354          // Confidential Asset types.
355          ("LegParty", &ink_enum_derives),
356          ("TransactionStatus", &ink_enum_derives),
357          ("TransactionId", &ink_id_derives),
358          ("TransactionLegId", &ink_id_derives),
359          ("ConfidentialAccount", &ink_id_derives),
360          ("MediatorAccount", &ink_id_derives),
361          ("ConfidentialTransactionRole", &ink_enum_derives),
362          ("CompressedElgamalPublicKey", &ink_id_derives),
363        ]
364        .into_iter()
365        .map(|(name, code)| (name.to_string(), code.clone())),
366      );
367
368      let mut gen = Self {
369        runtime_namespace: runtime_namespace.iter().cloned().collect(),
370        md,
371        external_modules,
372        pallet_types: BTreeMap::new(),
373        max_error_size: 4,
374        rename_types,
375        remap_namespaces,
376        ord_types: Default::default(),
377        custom_derives,
378        call,
379        event,
380        v2_weights: false,
381        api_interface,
382      };
383
384      // Process namespace remappings.
385      gen.remap_namespaces();
386
387      // Manually enable `Ord` for `Ticker`.
388      gen.ord_types.insert("Ticker".into());
389      // Try a limited number of times to mark all types needing the `Ord` type.
390      let mut ord_type_ids = BTreeSet::new();
391      for _ in 0..10 {
392        if !gen.check_for_ord_types(&mut ord_type_ids) {
393          // Finished, no new ord types.
394          break;
395        }
396      }
397      // Convert ord type ids to full names.
398      for id in ord_type_ids {
399        match gen.id_to_full_name(id) {
400          Some(name) if name != "Option" => {
401            gen.ord_types.insert(name);
402          }
403          _ => (),
404        }
405      }
406
407      gen.detect_v2_weights();
408
409      // Rename pallet types.
410      gen.rename_pallet_types();
411
412      gen
413    }
414
415    fn remap_namespaces(&mut self) {
416      for ty in self.md.types.types() {
417        let path = ty.ty.path();
418        let ns = path.namespace().join("::");
419        if ns.is_empty() {
420          continue;
421        }
422        if let Some(new_ns) = self.remap_namespaces.get(&ns) {
423          let name = path
424            .ident()
425            .expect("Namespace wasn't empty, so there should be an ident.");
426          let mut new_segments = new_ns
427            .split("::")
428            .map(|s| s.to_string())
429            .collect::<Vec<_>>();
430          new_segments.push(name.clone());
431          let old_name = format!("{ns}::{name}");
432          let new_name = segments_ident(&new_segments, false);
433          self.rename_types.insert(old_name, new_name);
434        }
435      }
436    }
437
438    fn rename_pallet_type(&mut self, id: u32, p_name: &str, kind: &str) {
439      let ty = self.md.types.resolve(id).unwrap();
440      let path = ty.path();
441      let mut segments: Vec<_> = path.segments().into_iter().cloned().collect();
442      let old_name = segments.join("::");
443      // pop ident.
444      segments.pop();
445
446      // Check for remapped namespace
447      let ns = segments.join("::");
448      if let Some(new_ns) = self.remap_namespaces.get(&ns) {
449        segments = new_ns.split("::").map(|s| s.to_string()).collect();
450      }
451
452      // Build new name.
453      let new_name = format!("{}{}", p_name, kind);
454      segments.push(new_name.clone());
455
456      // Add mapping from old name to new name.
457      let new_ident = segments_ident(&segments, false);
458      self.rename_types.insert(old_name, new_ident);
459      self.pallet_types.insert(id, (p_name.to_string(), new_name));
460    }
461
462    // Rename pallet types Call/Event/Error.
463    fn rename_pallet_types(&mut self) {
464      // Collect pallet type ids.
465      let types: Vec<_> = self
466        .md
467        .pallets
468        .iter()
469        .map(|p| {
470          (
471            p.name.to_string(),
472            p.calls.clone(),
473            p.event.clone(),
474            p.error.clone(),
475          )
476        })
477        .collect();
478      for (p_name, call, event, error) in types {
479        if let Some(c) = call {
480          self.rename_pallet_type(c.ty.id(), &p_name, "Call");
481        }
482        if let Some(e) = event {
483          self.rename_pallet_type(e.ty.id(), &p_name, "Event");
484        }
485        if let Some(e) = error {
486          self.rename_pallet_type(e.ty.id(), &p_name, "Error");
487        }
488      }
489    }
490
491    // Detect if chain is using V2 Weights.
492    fn detect_v2_weights(&mut self) {
493      for ty in self.md.types.types() {
494        let id = ty.id();
495        let full_name = self.id_to_full_name(id).unwrap_or_default();
496        if full_name == "frame_support::dispatch::DispatchInfo" {
497          self.v2_weights = true;
498          return;
499        }
500      }
501    }
502
503    fn id_to_full_name(&self, id: u32) -> Option<String> {
504      let ty = self.md.types.resolve(id)?;
505      let segments = ty.path().segments();
506      if segments.len() > 0 {
507        Some(segments.join("::"))
508      } else {
509        None
510      }
511    }
512
513    fn check_for_ord_types(&self, ord_type_ids: &mut BTreeSet<u32>) -> bool {
514      let count = ord_type_ids.len();
515      for ty in self.md.types.types() {
516        let id = ty.id();
517        let ty = ty.ty();
518        let full_name = self.id_to_full_name(id).unwrap_or_default();
519        // Check for `BTreeSet` and `BTreeMap`.
520        match full_name.as_str() {
521          "BTreeSet" | "BTreeMap" => {
522            // Mark the first type parameter as needing `Ord`.
523            ty.type_params()
524              .first()
525              .and_then(|param| param.ty())
526              .map(|ty| {
527                ord_type_ids.insert(ty.id());
528              });
529            continue;
530          }
531          _ => (),
532        }
533        // Check if this type needs `Ord`.
534        if ord_type_ids.contains(&id) {
535          // Mark fields and used types as needing `Ord`.
536          match ty.type_def() {
537            TypeDef::Composite(struct_ty) => {
538              for field in struct_ty.fields() {
539                ord_type_ids.insert(field.ty().id());
540              }
541            }
542            TypeDef::Variant(enum_ty) => {
543              for variant in enum_ty.variants() {
544                for field in variant.fields() {
545                  ord_type_ids.insert(field.ty().id());
546                }
547              }
548            }
549            TypeDef::Sequence(ty) => {
550              ord_type_ids.insert(ty.type_param().id());
551            }
552            TypeDef::Array(ty) => {
553              ord_type_ids.insert(ty.type_param().id());
554            }
555            TypeDef::Tuple(ty) => {
556              for field in ty.fields() {
557                ord_type_ids.insert(field.id());
558              }
559            }
560            TypeDef::Primitive(_) => (),
561            TypeDef::Compact(ty) => {
562              ord_type_ids.insert(ty.type_param().id());
563            }
564            _ => {}
565          }
566        }
567      }
568      let new_count = ord_type_ids.len();
569      count != new_count
570    }
571
572    fn is_boxed(field: &Field<PortableForm>) -> bool {
573      if let Some(type_name) = field.type_name() {
574        type_name.contains("Box<")
575      } else {
576        false
577      }
578    }
579
580    fn need_field_attributes(&self, field: &Field<PortableForm>) -> TokenStream {
581      if let Some(ty) = self.md.types.resolve(field.ty().id()) {
582        match ty.type_def() {
583          TypeDef::Compact(_) => {
584            return quote! { #[codec(compact)] };
585          }
586          TypeDef::Array(ty) => {
587            let len = ty.len() as usize;
588            if len > 32 {
589              return quote! { #[cfg_attr(feature = "serde", serde(with = "::serde_big_array::BigArray"))] };
590            }
591          }
592          _ => (),
593        }
594      }
595      quote! {}
596    }
597
598    fn type_name(&self, id: u32, compact_wrap: bool, import_types: bool) -> Option<TokenStream> {
599      let mut scope = TypeParameters::default();
600      self.type_name_scoped(id, &mut scope, compact_wrap, import_types)
601    }
602
603    fn type_name_scoped(
604      &self,
605      id: u32,
606      scope: &mut TypeParameters,
607      compact_wrap: bool,
608      import_types: bool,
609    ) -> Option<TokenStream> {
610      if let Some(scope_type) = scope.get_param(id) {
611        return Some(scope_type);
612      }
613      let ty = self.md.types.resolve(id)?;
614      let path = ty.path();
615      let (type_ident, is_btree) = match self.is_runtime_type(path) {
616        Some(name) => {
617          // Remap runtime types to namespace `runtime`.
618          let ident = format_ident!("{name}");
619          (quote!(runtime::#ident), false)
620        }
621        None => {
622          let segments = ty.path().segments();
623          let full_name = segments.join("::");
624          let is_btree = match full_name.as_str() {
625            "BTreeSet" | "BTreeMap" => true,
626            _ => false,
627          };
628          let type_ident = self
629            .rename_types
630            .get(&full_name)
631            .cloned()
632            .unwrap_or_else(|| segments_ident(segments, import_types));
633          (type_ident, is_btree)
634        }
635      };
636
637      match ty.type_def() {
638        TypeDef::Sequence(ty) => {
639          return self
640            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
641            .map(|elem_ty| {
642              quote! { ::alloc::vec::Vec<#elem_ty> }
643            });
644        }
645        TypeDef::Array(ty) => {
646          let len = ty.len() as usize;
647          return self
648            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
649            .map(|elem_ty| {
650              quote! { [#elem_ty; #len] }
651            });
652        }
653        TypeDef::Tuple(ty) => {
654          let fields = ty
655            .fields()
656            .into_iter()
657            .filter_map(|field| self.type_name_scoped(field.id(), scope, true, import_types))
658            .collect::<Vec<_>>();
659          return Some(quote! { (#(#fields),*) });
660        }
661        TypeDef::Primitive(prim) => {
662          use scale_info::TypeDefPrimitive::*;
663          let name = format_ident!(
664            "{}",
665            match prim {
666              Bool => "bool",
667              Char => "char",
668              Str => return Some(quote!(::alloc::string::String)),
669              U8 => "u8",
670              U16 => "u16",
671              U32 => "u32",
672              U64 => "u64",
673              U128 => "u128",
674              U256 => "u256",
675              I8 => "i8",
676              I16 => "i16",
677              I32 => "i32",
678              I64 => "i64",
679              I128 => "i128",
680              I256 => "i256",
681            }
682          );
683          return Some(quote! { #name });
684        }
685        TypeDef::Compact(ty) => {
686          return self
687            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
688            .map(|ty| {
689              if compact_wrap {
690                quote! { ::codec::Compact<#ty> }
691              } else {
692                ty
693              }
694            });
695        }
696        _ => {}
697      }
698
699      // Check if `BTreeSet` or `BTreeMap` use a scoped paramter for the key.
700      if is_btree {
701        ty.type_params()
702          .first()
703          .and_then(|param| param.ty())
704          .map(|ty| scope.add_param_bounds(ty.id(), "Ord", quote!(Ord)));
705      }
706
707      let type_params = ty
708        .type_params()
709        .iter()
710        .filter_map(|param| {
711          param
712            .ty()
713            .map(|ty| self.type_name_scoped(ty.id(), scope, true, import_types))
714        })
715        .collect::<Vec<_>>();
716
717      if type_params.len() > 0 {
718        Some(quote! {
719          #type_ident<#(#type_params),*>
720        })
721      } else {
722        Some(type_ident)
723      }
724    }
725
726    fn gen_storage_func(
727      &self,
728      mod_prefix: &str,
729      md: &StorageEntryMetadata<PortableForm>,
730    ) -> TokenStream {
731      let storage_name = &md.name;
732      let storage_ident = format_ident!("{}", storage_name.to_snake_case());
733      let api_interface = &self.api_interface;
734      let mut key_prefix = Vec::with_capacity(512);
735      key_prefix.extend(sp_core_hashing::twox_128(mod_prefix.as_bytes()));
736      key_prefix.extend(sp_core_hashing::twox_128(storage_name.as_bytes()));
737
738      let (hashers, value_ty) = match &md.ty {
739        StorageEntryType::Plain(value) => (vec![], value.id()),
740        StorageEntryType::Map {
741          hashers,
742          key,
743          value,
744        } => match hashers.as_slice() {
745          [hasher] => {
746            // 1 key.
747            (vec![(key, hasher)], value.id())
748          }
749          hashers => {
750            // >=2 keys.
751            let keys_ty = self.md.types.resolve(key.id()).unwrap();
752            let key_hashers = if let TypeDef::Tuple(ty) = keys_ty.type_def() {
753              ty.fields().iter().zip(hashers).collect()
754            } else {
755              vec![]
756            };
757            (key_hashers, value.id())
758          }
759        },
760      };
761      let keys_len = hashers.len();
762      let mut keys = TokenStream::new();
763      let mut hashing = TokenStream::new();
764      for (idx, (key, hasher)) in hashers.into_iter().enumerate() {
765        let key_ident = format_ident!("key_{}", idx);
766        let type_name = self
767          .type_name(key.id(), false, true)
768          .expect("Missing Storage key type");
769        keys.append_all(quote! {#key_ident: #type_name,});
770        hashing.append_all(match hasher {
771          StorageHasher::Blake2_128 => quote! {
772            buf.extend(#api_interface::hashing::blake2_128(&#key_ident.encode()));
773          },
774          StorageHasher::Blake2_256 => quote! {
775            buf.extend(#api_interface::hashing::blake2_256(&#key_ident.encode()));
776          },
777          StorageHasher::Blake2_128Concat => quote! {
778            let key = #key_ident.encode();
779            buf.extend(#api_interface::hashing::blake2_128(&key));
780            buf.extend(key.into_iter());
781          },
782          StorageHasher::Twox128 => quote! {
783            buf.extend(#api_interface::hashing::twox_128(&#key_ident.encode()));
784          },
785          StorageHasher::Twox256 => quote! {
786            buf.extend(#api_interface::hashing::twox_256(&#key_ident.encode()));
787          },
788          StorageHasher::Twox64Concat => quote! {
789            let key = #key_ident.encode();
790            buf.extend(#api_interface::hashing::twox_64(&key));
791            buf.extend(key.into_iter());
792          },
793          StorageHasher::Identity => quote! {
794            buf.extend(#key_ident.encode());
795          },
796        });
797      }
798      let value_ty = if mod_prefix == "System" && storage_name == "Events" {
799        let event_ty = &self.event;
800        quote!(::alloc::vec::Vec<#api_interface::EventRecord<types::#event_ty>>)
801      } else {
802        self.type_name(value_ty, false, true).unwrap()
803      };
804
805      let (return_ty, return_value) = match md.modifier {
806        StorageEntryModifier::Optional => (quote! { Option<#value_ty>}, quote! { Ok(value) }),
807        StorageEntryModifier::Default => {
808          let default_value = &md.default;
809          (
810            quote! { #value_ty },
811            quote! {
812              Ok(value.unwrap_or_else(|| {
813                use ::codec::Decode;
814                const DEFAULT: &'static [u8] = &[#(#default_value,)*];
815                <#value_ty>::decode(&mut &DEFAULT[..]).unwrap()
816              }))
817            },
818          )
819        }
820      };
821
822      let docs = &md.docs;
823      if keys_len > 0 {
824        quote! {
825          #(#[doc = #docs])*
826          #[cfg(not(feature = "ink"))]
827          pub async fn #storage_ident(&self, #keys) -> ::polymesh_api_client::error::Result<#return_ty> {
828            use ::codec::Encode;
829            let mut buf = ::alloc::vec::Vec::with_capacity(512);
830            buf.extend([#(#key_prefix,)*]);
831            #hashing
832            let key = ::polymesh_api_client::StorageKey(buf);
833            let value = self.api.client.get_storage_by_key(key, self.at).await?;
834            #return_value
835          }
836
837          #(#[doc = #docs])*
838          #[cfg(feature = "ink")]
839          pub fn #storage_ident(&self, #keys) -> ::polymesh_api_ink::error::Result<#return_ty> {
840            use ::codec::Encode;
841            let mut buf = ::alloc::vec::Vec::with_capacity(512);
842            buf.extend([#(#key_prefix,)*]);
843            #hashing
844            let value = self.api.read_storage(buf)?;
845            #return_value
846          }
847        }
848      } else {
849        quote! {
850          #(#[doc = #docs])*
851          #[cfg(not(feature = "ink"))]
852          pub async fn #storage_ident(&self) -> ::polymesh_api_client::error::Result<#return_ty> {
853            let key = ::polymesh_api_client::StorageKey(::alloc::vec![#(#key_prefix,)*]);
854            let value = self.api.client.get_storage_by_key(key, self.at).await?;
855            #return_value
856          }
857
858          #(#[doc = #docs])*
859          #[cfg(feature = "ink")]
860          pub fn #storage_ident(&self) -> ::polymesh_api_ink::error::Result<#return_ty> {
861            let value = self.api.read_storage(::alloc::vec![#(#key_prefix,)*])?;
862            #return_value
863          }
864        }
865      }
866    }
867
868    fn gen_paged_storage_func(
869      &self,
870      mod_prefix: &str,
871      md: &StorageEntryMetadata<PortableForm>,
872    ) -> TokenStream {
873      let storage_name = &md.name;
874      let storage_ident = format_ident!("{}", storage_name.to_snake_case());
875      let api_interface = &self.api_interface;
876      let mut key_prefix = Vec::with_capacity(32);
877      key_prefix.extend(sp_core_hashing::twox_128(mod_prefix.as_bytes()));
878      key_prefix.extend(sp_core_hashing::twox_128(storage_name.as_bytes()));
879
880      let (mut hashers, value_ty) = match &md.ty {
881        StorageEntryType::Plain(value) => (vec![], value.id()),
882        StorageEntryType::Map {
883          hashers,
884          key,
885          value,
886        } => match hashers.as_slice() {
887          [hasher] => {
888            // 1 key.
889            (vec![(key, hasher)], value.id())
890          }
891          hashers => {
892            // >=2 keys.
893            let keys_ty = self.md.types.resolve(key.id()).unwrap();
894            let key_hashers = if let TypeDef::Tuple(ty) = keys_ty.type_def() {
895              ty.fields().iter().zip(hashers).collect()
896            } else {
897              vec![]
898            };
899            (key_hashers, value.id())
900          }
901        },
902      };
903      // Get the last key_hasher.
904      let (key_ty, key_hash_len) = if let Some((key, hasher)) = hashers.pop() {
905        let type_name = self
906          .type_name(key.id(), false, true)
907          .expect("Missing Storage key type");
908        let hash_len = match hasher {
909          StorageHasher::Blake2_128Concat => quote! { Some(16) },
910          StorageHasher::Twox64Concat => quote! { Some(8) },
911          StorageHasher::Identity => quote! { Some(0) },
912          _ => quote! { None },
913        };
914        (type_name, hash_len)
915      } else {
916        return quote! {};
917      };
918      let mut keys = TokenStream::new();
919      let mut hashing = TokenStream::new();
920      for (idx, (key, hasher)) in hashers.into_iter().enumerate() {
921        let key_ident = format_ident!("key_{}", idx);
922        let type_name = self
923          .type_name(key.id(), false, true)
924          .expect("Missing Storage key type");
925        keys.append_all(quote! {#key_ident: #type_name,});
926        hashing.append_all(match hasher {
927          StorageHasher::Blake2_128 => quote! {
928            buf.extend(#api_interface::hashing::blake2_128(&#key_ident.encode()));
929          },
930          StorageHasher::Blake2_256 => quote! {
931            buf.extend(#api_interface::hashing::blake2_256(&#key_ident.encode()));
932          },
933          StorageHasher::Blake2_128Concat => quote! {
934            let key = #key_ident.encode();
935            buf.extend(#api_interface::hashing::blake2_128(&key));
936            buf.extend(key.into_iter());
937          },
938          StorageHasher::Twox128 => quote! {
939            buf.extend(#api_interface::hashing::twox_128(&#key_ident.encode()));
940          },
941          StorageHasher::Twox256 => quote! {
942            buf.extend(#api_interface::hashing::twox_256(&#key_ident.encode()));
943          },
944          StorageHasher::Twox64Concat => quote! {
945            let key = #key_ident.encode();
946            buf.extend(#api_interface::hashing::twox_64(&key));
947            buf.extend(key.into_iter());
948          },
949          StorageHasher::Identity => quote! {
950            buf.extend(#key_ident.encode());
951          },
952        });
953      }
954      let value_ty = self.type_name(value_ty, false, true).unwrap();
955
956      let docs = &md.docs;
957      quote! {
958        #(#[doc = #docs])*
959        pub fn #storage_ident(&self, #keys) -> ::polymesh_api_client::StoragePaged<#key_ty, #value_ty> {
960          use ::codec::Encode;
961          let mut buf = ::alloc::vec::Vec::with_capacity(512);
962          buf.extend([#(#key_prefix,)*]);
963          #hashing
964          let prefix = ::polymesh_api_client::StorageKey(buf);
965          ::polymesh_api_client::StoragePaged::new(&self.api.client, prefix, #key_hash_len, self.at)
966        }
967      }
968    }
969
970    fn gen_func(
971      &self,
972      mod_name: &str,
973      mod_idx: u8,
974      mod_call_ty: u32,
975      md: &Variant<PortableForm>,
976    ) -> TokenStream {
977      let mod_call_ident = format_ident!("{mod_name}");
978      let mod_call = self.type_name(mod_call_ty, false, true).unwrap();
979      let func_name = md.name();
980      let func_idx = md.index();
981      let func_ident = format_ident!("{}", func_name.to_snake_case());
982
983      let mut fields = TokenStream::new();
984      let mut field_names = TokenStream::new();
985      let mut fields_encode = TokenStream::new();
986      for (idx, field) in md.fields().iter().enumerate() {
987        let name = field
988          .name()
989          .map(|n| format_ident!("{n}"))
990          .unwrap_or_else(|| format_ident!("param_{idx}"));
991        let type_name = self
992          .type_name(field.ty().id(), false, true)
993          .expect("Missing Extrinsic param type");
994        fields.append_all(quote! {#name: #type_name,});
995        if Self::is_boxed(field) {
996          field_names.append_all(quote! {#name: ::alloc::boxed::Box::new(#name),});
997        } else {
998          field_names.append_all(quote! {#name,});
999        }
1000        fields_encode.append_all(quote! {
1001          #name.encode_to(&mut buf);
1002        });
1003      }
1004
1005      let docs = md.docs();
1006      let call_ty = &self.call;
1007      if md.fields().len() > 0 {
1008        quote! {
1009          #(#[doc = #docs])*
1010          #[cfg(not(feature = "ink"))]
1011          pub fn #func_ident(&self, #fields) -> ::polymesh_api_client::error::Result<super::super::WrappedCall> {
1012            self.api.wrap_call(#call_ty::#mod_call_ident(types::#mod_call::#func_ident { #field_names }))
1013          }
1014
1015          #(#[doc = #docs])*
1016          #[cfg(feature = "ink")]
1017          pub fn #func_ident(&self, #fields) -> super::super::WrappedCall {
1018            use ::codec::Encode;
1019            let mut buf = ::alloc::vec![#mod_idx, #func_idx];
1020            #fields_encode
1021            self.api.wrap_call(buf)
1022          }
1023        }
1024      } else {
1025        quote! {
1026          #(#[doc = #docs])*
1027          #[cfg(not(feature = "ink"))]
1028          pub fn #func_ident(&self) -> ::polymesh_api_client::error::Result<super::super::WrappedCall> {
1029            self.api.wrap_call(#call_ty::#mod_call_ident(types::#mod_call::#func_ident))
1030          }
1031
1032          #(#[doc = #docs])*
1033          #[cfg(feature = "ink")]
1034          pub fn #func_ident(&self) -> super::super::WrappedCall {
1035            self.api.wrap_call(::alloc::vec![#mod_idx, #func_idx])
1036          }
1037        }
1038      }
1039    }
1040
1041    fn gen_module(
1042      &self,
1043      md: &frame_metadata::v14::PalletMetadata<PortableForm>,
1044    ) -> (Ident, Ident, Ident, Ident, TokenStream) {
1045      let mod_idx = md.index;
1046      let mod_name = &md.name;
1047      let mod_call_api = format_ident!("{}CallApi", mod_name);
1048      let mod_query_api = format_ident!("{}QueryApi", mod_name);
1049      let mod_paged_query_api = format_ident!("{}PagedQueryApi", mod_name);
1050      let mod_ident = format_ident!("{}", mod_name.to_snake_case());
1051
1052      let mut call_fields = TokenStream::new();
1053      let mut query_fields = TokenStream::new();
1054      let mut paged_query_fields = TokenStream::new();
1055
1056      // Generate module functions.
1057      if let Some(calls) = &md.calls {
1058        let call_ty = self
1059          .md
1060          .types
1061          .resolve(calls.ty.id())
1062          .expect("Missing Pallet call type");
1063        match call_ty.type_def() {
1064          TypeDef::Variant(v) => {
1065            let mod_call_ty = calls.ty.id();
1066            for v in v.variants() {
1067              let code = self.gen_func(mod_name, mod_idx, mod_call_ty, v);
1068              call_fields.append_all(code);
1069            }
1070          }
1071          _ => {
1072            unimplemented!("Only Variant type supported for Pallet Call type.");
1073          }
1074        }
1075      }
1076
1077      // Generate module storage query functions.
1078      if let Some(storage) = &md.storage {
1079        let mod_prefix = &storage.prefix;
1080        for md in &storage.entries {
1081          query_fields.append_all(self.gen_storage_func(mod_prefix, md));
1082          paged_query_fields.append_all(self.gen_paged_storage_func(mod_prefix, md));
1083        }
1084      }
1085
1086      let code = quote! {
1087        pub mod #mod_ident {
1088          use super::*;
1089
1090          #[derive(Clone)]
1091          pub struct #mod_call_api<'api> {
1092            api: &'api super::super::Api,
1093          }
1094
1095          impl<'api> #mod_call_api<'api> {
1096            #call_fields
1097          }
1098
1099          impl<'api> From<&'api super::super::Api> for #mod_call_api<'api> {
1100            fn from(api: &'api super::super::Api) -> Self {
1101              Self { api }
1102            }
1103          }
1104
1105          #[derive(Clone)]
1106          pub struct #mod_query_api<'api> {
1107            pub(crate) api: &'api super::super::Api,
1108            #[cfg(not(feature = "ink"))]
1109            pub(crate) at: Option<::polymesh_api_client::BlockHash>,
1110          }
1111
1112          impl<'api> #mod_query_api<'api> {
1113            #query_fields
1114          }
1115
1116          #[derive(Clone)]
1117          #[cfg(not(feature = "ink"))]
1118          pub struct #mod_paged_query_api<'api> {
1119            pub(crate) api: &'api super::super::Api,
1120            pub(crate) at: Option<::polymesh_api_client::BlockHash>,
1121          }
1122
1123          #[cfg(not(feature = "ink"))]
1124          impl<'api> #mod_paged_query_api<'api> {
1125            #paged_query_fields
1126          }
1127        }
1128      };
1129      (
1130        mod_ident,
1131        mod_call_api,
1132        mod_query_api,
1133        mod_paged_query_api,
1134        code,
1135      )
1136    }
1137
1138    fn gen_struct_fields(
1139      &self,
1140      fields: &[Field<PortableForm>],
1141      scope: &mut TypeParameters,
1142    ) -> Option<(bool, TokenStream)> {
1143      let mut is_tuple = false;
1144      let mut named = Vec::new();
1145      let mut unnamed = Vec::new();
1146
1147      // Check for unit type (i.e. empty field list).
1148      if fields.len() == 0 {
1149        return Some((true, quote! {}));
1150      }
1151
1152      for field in fields {
1153        let mut field_ty = self.type_name_scoped(field.ty().id(), scope, false, false)?;
1154        if Self::is_boxed(field) {
1155          field_ty = quote!(::alloc::boxed::Box<#field_ty>);
1156        }
1157        let attr = self.need_field_attributes(field);
1158        unnamed.push(quote! { #attr pub #field_ty });
1159        if let Some(name) = field.name() {
1160          let docs = field.docs();
1161          let name = format_ident!("{name}");
1162          named.push(quote! {
1163              #(#[doc = #docs])*
1164              #attr
1165              pub #name: #field_ty
1166          });
1167        } else {
1168          // If there are any unnamed fields, then make it a tuple.
1169          is_tuple = true;
1170        }
1171      }
1172
1173      if is_tuple {
1174        Some((true, quote! { #(#unnamed),* }))
1175      } else {
1176        Some((
1177          false,
1178          quote! {
1179            #(#named),*
1180          },
1181        ))
1182      }
1183    }
1184
1185    fn gen_enum_match_fields(&self, fields: &[Field<PortableForm>]) -> TokenStream {
1186      let mut is_tuple = false;
1187      let mut unnamed = Vec::new();
1188
1189      // Check for unit type (i.e. empty field list).
1190      if fields.len() == 0 {
1191        return quote!();
1192      }
1193
1194      for field in fields {
1195        unnamed.push(quote!(_));
1196        if field.name().is_none() {
1197          // If there are any unnamed fields, then make it a tuple.
1198          is_tuple = true;
1199        }
1200      }
1201
1202      if is_tuple {
1203        quote! { (#(#unnamed),*) }
1204      } else {
1205        quote! {
1206          {
1207            ..
1208          }
1209        }
1210      }
1211    }
1212
1213    fn gen_enum_fields(
1214      &self,
1215      fields: &[Field<PortableForm>],
1216      scope: &mut TypeParameters,
1217    ) -> Option<(bool, Vec<TokenStream>)> {
1218      let mut is_tuple = false;
1219      let mut named = Vec::new();
1220      let mut unnamed = Vec::new();
1221
1222      // Check for unit type (i.e. empty field list).
1223      if fields.len() == 0 {
1224        return Some((true, unnamed));
1225      }
1226
1227      for field in fields {
1228        let mut field_ty = self.type_name_scoped(field.ty().id(), scope, false, false)?;
1229        if Self::is_boxed(field) {
1230          field_ty = quote!(::alloc::boxed::Box<#field_ty>);
1231        }
1232        let docs = field.docs();
1233        let attr = self.need_field_attributes(field);
1234        unnamed.push(quote! {
1235            #(#[doc = #docs])*
1236            #attr
1237            #field_ty
1238        });
1239        if let Some(name) = field.name() {
1240          let name = format_ident!("{name}");
1241          named.push(quote! {
1242              #(#[doc = #docs])*
1243              #attr
1244              #name: #field_ty
1245          });
1246        } else {
1247          // If there are any unnamed fields, then make it a tuple.
1248          is_tuple = true;
1249        }
1250      }
1251
1252      if is_tuple {
1253        Some((true, unnamed))
1254      } else {
1255        Some((false, named))
1256      }
1257    }
1258
1259    fn gen_enum_as_static_str(
1260      &self,
1261      ty_ident: &Ident,
1262      params: &TokenStream,
1263      ty: &Type<PortableForm>,
1264      prefix: Option<&String>,
1265    ) -> Option<TokenStream> {
1266      let mut as_str_arms = TokenStream::new();
1267      let mut as_docs_arms = TokenStream::new();
1268      match (prefix, ty.type_def()) {
1269        (None, TypeDef::Variant(enum_ty)) => {
1270          for variant in enum_ty.variants() {
1271            let top_name = variant.name();
1272            let top_ident = format_ident!("{}", top_name);
1273            let fields = variant.fields().len();
1274            match fields {
1275              0 => {
1276                as_str_arms.append_all(quote! {
1277                  Self::#top_ident => {
1278                    #top_name
1279                  },
1280                });
1281                as_docs_arms.append_all(quote! {
1282                  Self::#top_ident => {
1283                    &[""]
1284                  },
1285                });
1286              }
1287              1 => {
1288                as_str_arms.append_all(quote! {
1289                  Self::#top_ident(val) => {
1290                    val.as_static_str()
1291                  },
1292                });
1293                as_docs_arms.append_all(quote! {
1294                  Self::#top_ident(val) => {
1295                    val.as_docs()
1296                  },
1297                });
1298              }
1299              _ => {
1300                as_str_arms.append_all(quote! {
1301                  Self::#top_ident(_) => {
1302                    #top_name
1303                  },
1304                });
1305                as_docs_arms.append_all(quote! {
1306                  Self::#top_ident(_) => {
1307                    &[""]
1308                  },
1309                });
1310              }
1311            }
1312          }
1313        }
1314        (Some(prefix), TypeDef::Variant(enum_ty)) => {
1315          for variant in enum_ty.variants() {
1316            let var_name = variant.name();
1317            let var_ident = format_ident!("{}", var_name);
1318            let mut docs = variant.docs().to_vec();
1319            if docs.len() == 0 {
1320              docs.push("".to_string());
1321            }
1322            let as_str_name = format!("{}.{}", prefix, var_name);
1323            let match_fields = self.gen_enum_match_fields(variant.fields());
1324            as_str_arms.append_all(quote! {
1325              Self:: #var_ident #match_fields => {
1326                #as_str_name
1327              },
1328            });
1329            as_docs_arms.append_all(quote! {
1330              Self:: #var_ident #match_fields => {
1331                &[#(#docs,)*]
1332              },
1333            });
1334          }
1335        }
1336        _ => {
1337          return None;
1338        }
1339      };
1340      Some(quote! {
1341        impl #params #ty_ident #params {
1342          pub fn as_static_str(&self) -> &'static str {
1343            #[allow(unreachable_patterns)]
1344            match self {
1345              #as_str_arms
1346              _ => "Unknown",
1347            }
1348          }
1349        }
1350
1351        #[cfg(not(feature = "ink"))]
1352        impl #params ::polymesh_api_client::EnumInfo for #ty_ident #params {
1353          fn as_name(&self) -> &'static str {
1354            self.as_static_str()
1355          }
1356
1357          fn as_docs(&self) -> &'static [&'static str] {
1358            #[allow(unreachable_patterns)]
1359            match self {
1360              #as_docs_arms
1361              _ => &[""],
1362            }
1363          }
1364        }
1365
1366        impl #params From<#ty_ident #params> for &'static str {
1367          fn from(v: #ty_ident #params) -> Self {
1368            v.as_static_str()
1369          }
1370        }
1371
1372        impl #params From<&#ty_ident #params> for &'static str {
1373          fn from(v: &#ty_ident #params) -> Self {
1374            v.as_static_str()
1375          }
1376        }
1377      })
1378    }
1379
1380    fn is_runtime_type(&self, path: &Path<PortableForm>) -> Option<String> {
1381      if self.runtime_namespace == path.namespace() {
1382        let ident = path.ident();
1383        match ident.as_deref() {
1384          Some("Event") => Some("RuntimeEvent".into()),
1385          Some("Call") => Some("RuntimeCall".into()),
1386          Some(name) => Some(name.into()),
1387          _ => None,
1388        }
1389      } else {
1390        None
1391      }
1392    }
1393
1394    fn gen_module_error(
1395      &self,
1396      _id: u32,
1397      ty: &Type<PortableForm>,
1398      ident: &str,
1399    ) -> Option<TokenStream> {
1400      let ty_ident = format_ident!("{ident}");
1401      let mut scope = TypeParameters::new(ty);
1402
1403      let mut variants = TokenStream::new();
1404      let mut as_str_arms = TokenStream::new();
1405      let mut as_docs_arms = TokenStream::new();
1406      for p in &self.md.pallets {
1407        let idx = p.index;
1408        let mod_ident = format_ident!("{}", p.name);
1409        let error_ty = p.error.as_ref().and_then(|e| {
1410          self
1411            .type_name_scoped(e.ty.id(), &mut scope, false, false)
1412            .map(|ident| quote! { (#ident) })
1413        });
1414        if let Some(error_ty) = error_ty {
1415          variants.append_all(quote! {
1416            #[codec(index = #idx)]
1417            #mod_ident #error_ty,
1418          });
1419          as_str_arms.append_all(quote! {
1420            RuntimeError:: #mod_ident(err) => err.as_static_str(),
1421          });
1422          as_docs_arms.append_all(quote! {
1423            RuntimeError:: #mod_ident(err) => err.as_docs(),
1424          });
1425        }
1426      }
1427
1428      let docs = ty.docs();
1429      let max_error_size = self.max_error_size + 1;
1430      let code = quote! {
1431        #[derive(Clone, Debug, PartialEq, Eq)]
1432        #[derive(::codec::Encode, ::codec::Decode)]
1433        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1434        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1435        pub enum RuntimeError {
1436          #variants
1437        }
1438
1439        impl RuntimeError {
1440          pub fn as_static_str(&self) -> &'static str {
1441            match self {
1442              #as_str_arms
1443            }
1444          }
1445        }
1446
1447        impl From<RuntimeError> for &'static str {
1448          fn from(v: RuntimeError) -> Self {
1449            v.as_static_str()
1450          }
1451        }
1452
1453        impl From<&RuntimeError> for &'static str {
1454          fn from(v: &RuntimeError) -> Self {
1455            v.as_static_str()
1456          }
1457        }
1458
1459        #[cfg(not(feature = "ink"))]
1460        impl ::polymesh_api_client::EnumInfo for RuntimeError {
1461          fn as_name(&self) -> &'static str {
1462            self.as_static_str()
1463          }
1464
1465          fn as_docs(&self) -> &'static [&'static str] {
1466            match self {
1467              #as_docs_arms
1468            }
1469          }
1470        }
1471
1472        #(#[doc = #docs])*
1473        #[derive(Clone, Debug, PartialEq, Eq)]
1474        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1475        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1476        pub struct #ty_ident(pub RuntimeError);
1477
1478        impl ::codec::Encode for #ty_ident {
1479          fn encode_to<T: ::codec::Output + ?Sized>(&self, output: &mut T) {
1480            let mut raw = self.0.encode();
1481            raw.resize(#max_error_size, 0);
1482            output.write(raw.as_slice());
1483          }
1484        }
1485
1486        impl ::codec::Decode for #ty_ident {
1487          fn decode<I: ::codec::Input>(input: &mut I) -> Result<Self, ::codec::Error> {
1488            let raw: [u8; #max_error_size] = ::codec::Decode::decode(input)?;
1489            Ok(Self(RuntimeError::decode(&mut &raw[..])?))
1490          }
1491        }
1492
1493        impl #ty_ident {
1494          pub fn as_static_str(&self) -> &'static str {
1495            self.0.as_static_str()
1496          }
1497        }
1498
1499        impl From<#ty_ident> for &'static str {
1500          fn from(v: #ty_ident) -> Self {
1501            v.as_static_str()
1502          }
1503        }
1504
1505        impl From<&#ty_ident> for &'static str {
1506          fn from(v: &#ty_ident) -> Self {
1507            v.as_static_str()
1508          }
1509        }
1510
1511        #[cfg(not(feature = "ink"))]
1512        impl ::polymesh_api_client::EnumInfo for #ty_ident {
1513          fn as_name(&self) -> &'static str {
1514            self.as_static_str()
1515          }
1516
1517          fn as_docs(&self) -> &'static [&'static str] {
1518            self.0.as_docs()
1519          }
1520        }
1521      };
1522      Some(code)
1523    }
1524
1525    fn gen_dispatch_error(
1526      &self,
1527      _id: u32,
1528      ty: &Type<PortableForm>,
1529      ident: &str,
1530    ) -> Option<TokenStream> {
1531      let ty_ident = format_ident!("{ident}");
1532      let mut scope = TypeParameters::new(ty);
1533
1534      let mut variants = TokenStream::new();
1535      let mut as_str_arms = TokenStream::new();
1536      let mut as_docs_arms = TokenStream::new();
1537      for p in &self.md.pallets {
1538        let idx = p.index;
1539        let mod_ident = format_ident!("{}", p.name);
1540        let error_ty = p.error.as_ref().and_then(|e| {
1541          self
1542            .type_name_scoped(e.ty.id(), &mut scope, false, false)
1543            .map(|ident| quote! { (#ident) })
1544        });
1545        if let Some(error_ty) = error_ty {
1546          variants.append_all(quote! {
1547            #[codec(index = #idx)]
1548            #mod_ident #error_ty,
1549          });
1550          as_str_arms.append_all(quote! {
1551            RuntimeError:: #mod_ident(err) => err.as_static_str(),
1552          });
1553          as_docs_arms.append_all(quote! {
1554            RuntimeError:: #mod_ident(err) => err.as_docs(),
1555          });
1556        }
1557      }
1558
1559      let docs = ty.docs();
1560      let code = quote! {
1561        #(#[doc = #docs])*
1562        #[derive(Clone, Debug, PartialEq, Eq)]
1563        #[derive(::codec::Encode, ::codec::Decode)]
1564        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1565        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1566        pub enum #ty_ident {
1567          Other,
1568          CannotLookup,
1569          BadOrigin,
1570          Module(ModuleError),
1571          ConsumerRemaining,
1572          NoProviders,
1573          TooManyConsumers,
1574          Token(sp_runtime::TokenError),
1575          Arithmetic(sp_arithmetic::ArithmeticError),
1576          Transactional(sp_runtime::TransactionalError),
1577          Exhausted,
1578          Corruption,
1579          Unavailable,
1580          RootNotAllowed,
1581        }
1582
1583        impl #ty_ident {
1584          pub fn as_static_str(&self) -> &'static str {
1585            match self {
1586              Self::Other => "Other",
1587              Self::CannotLookup => "CannotLookup",
1588              Self::BadOrigin => "BadOrigin",
1589              Self::Module(err) => err.as_static_str(),
1590              Self::ConsumerRemaining => "ConsumerRemaining",
1591              Self::NoProviders => "NoProviders",
1592              Self::TooManyConsumers => "TooManyConsumers",
1593              Self::Token(err) => err.as_static_str(),
1594              Self::Arithmetic(err) => err.as_static_str(),
1595              Self::Transactional(err) => err.as_static_str(),
1596              Self::Exhausted => "Exhausted",
1597              Self::Corruption => "Corruption",
1598              Self::Unavailable => "Unavailable",
1599              Self::RootNotAllowed => "RootNotAllowed",
1600            }
1601          }
1602        }
1603
1604        impl From<#ty_ident> for &'static str {
1605          fn from(v: #ty_ident) -> Self {
1606            v.as_static_str()
1607          }
1608        }
1609
1610        impl From<&#ty_ident> for &'static str {
1611          fn from(v: &#ty_ident) -> Self {
1612            v.as_static_str()
1613          }
1614        }
1615
1616        #[cfg(not(feature = "ink"))]
1617        impl ::polymesh_api_client::EnumInfo for #ty_ident {
1618          fn as_name(&self) -> &'static str {
1619            self.as_static_str()
1620          }
1621
1622          fn as_docs(&self) -> &'static [&'static str] {
1623            match self {
1624              Self::Other => &["Some error occurred."],
1625              Self::CannotLookup => &["Failed to lookup some data."],
1626              Self::BadOrigin => &["A bad origin."],
1627              Self::Module(err) => err.as_docs(),
1628              Self::ConsumerRemaining => &["At least one consumer is remaining so the account cannot be destroyed."],
1629              Self::NoProviders => &["There are no providers so the account cannot be created."],
1630              Self::TooManyConsumers => &["There are too many consumers so the account cannot be created."],
1631              Self::Token(err) => err.as_docs(),
1632              Self::Arithmetic(err) => err.as_docs(),
1633              Self::Transactional(err) => err.as_docs(),
1634              Self::Exhausted => &["Resources exhausted, e.g. attempt to read/write data which is too large to manipulate."],
1635              Self::Corruption => &["The state is corrupt; this is generally not going to fix itself."],
1636              Self::Unavailable => &["Some resource (e.g. a preimage) is unavailable right now. This might fix itself later."],
1637              Self::RootNotAllowed => &["Root origin is not allowed."],
1638            }
1639          }
1640        }
1641      };
1642      Some(code)
1643    }
1644
1645    fn gen_type(
1646      &self,
1647      id: u32,
1648      ty: &Type<PortableForm>,
1649      ident: &str,
1650      is_runtime_type: bool,
1651    ) -> Option<TokenStream> {
1652      let full_name = self.id_to_full_name(id)?;
1653      if full_name == "sp_runtime::ModuleError" {
1654        return self.gen_module_error(id, ty, ident);
1655      }
1656      if full_name == "sp_runtime::DispatchError" {
1657        return self.gen_dispatch_error(id, ty, ident);
1658      }
1659      let (pallet_name, ident) = match self.pallet_types.get(&id) {
1660        Some((pallet_name, ident)) => (Some(pallet_name), ident.as_str()),
1661        None => (None, ident),
1662      };
1663      let ty_ident = format_ident!("{ident}");
1664
1665      let mut scope = TypeParameters::new(ty);
1666      let derive_ord = if self.ord_types.contains(&full_name) {
1667        quote! {
1668          #[derive(PartialOrd, Ord)]
1669        }
1670      } else {
1671        quote!()
1672      };
1673      let custom_derive = self
1674        .custom_derives
1675        .get(ident)
1676        .cloned()
1677        .unwrap_or_else(|| quote!());
1678
1679      let docs = ty.docs();
1680      let (mut code, params) = match ty.type_def() {
1681        TypeDef::Composite(struct_ty) => {
1682          let (is_tuple, mut fields) = self.gen_struct_fields(struct_ty.fields(), &mut scope)?;
1683          if let Some(unused_params) = scope.get_unused_params() {
1684            if is_tuple {
1685              fields.append_all(quote! {
1686                , #unused_params
1687              });
1688            } else {
1689              fields.append_all(quote! {
1690                , _phantom_data: #unused_params
1691              });
1692            }
1693          }
1694          let params = scope.get_type_params();
1695          if is_tuple {
1696            (
1697              quote! {
1698                #(#[doc = #docs])*
1699                #[derive(Clone, Debug, PartialEq, Eq)]
1700                #derive_ord
1701                #custom_derive
1702                #[derive(::codec::Encode, ::codec::Decode)]
1703                #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1704                #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1705                pub struct #ty_ident #params (#fields);
1706              },
1707              params,
1708            )
1709          } else {
1710            (
1711              quote! {
1712                #(#[doc = #docs])*
1713                #[derive(Clone, Debug, PartialEq, Eq)]
1714                #derive_ord
1715                #custom_derive
1716                #[derive(::codec::Encode, ::codec::Decode)]
1717                #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1718                #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1719                pub struct #ty_ident #params { #fields }
1720              },
1721              params,
1722            )
1723          }
1724        }
1725        TypeDef::Variant(enum_ty) => {
1726          let mut variants = TokenStream::new();
1727          let mut runtime_events = TokenStream::new();
1728          let is_runtime_event = is_runtime_type && ident == "RuntimeEvent";
1729          for variant in enum_ty.variants() {
1730            let idx = variant.index();
1731            let docs = variant.docs();
1732            let name = variant.name();
1733            let ident = format_ident!("{}", name);
1734            let (is_tuple, fields) = self.gen_enum_fields(variant.fields(), &mut scope)?;
1735            let variant_ty = if is_runtime_event {
1736              let event_ident = format_ident!("{}Event", name);
1737              runtime_events.append_all(quote! {
1738                pub type #event_ident = #(#fields),*;
1739              });
1740              quote! {
1741                (events::#event_ident),
1742              }
1743            } else {
1744              if is_tuple {
1745                if fields.len() > 0 {
1746                  quote! { (#(#fields),*), }
1747                } else {
1748                  quote! { , }
1749                }
1750              } else {
1751                quote! {
1752                  {
1753                    #(#fields),*
1754                  },
1755                }
1756              }
1757            };
1758            variants.append_all(quote! {
1759              #(#[doc = #docs])*
1760              #[codec(index = #idx)]
1761              #ident #variant_ty
1762            });
1763          }
1764          if let Some(unused_params) = scope.get_unused_params() {
1765            variants.append_all(quote! {
1766              PhantomDataVariant(#unused_params)
1767            });
1768          }
1769          if is_runtime_event {
1770            runtime_events = quote! {
1771              pub mod events {
1772                use super::*;
1773                #runtime_events
1774              }
1775            }
1776          }
1777          let params = scope.get_type_params();
1778          (
1779            quote! {
1780              #runtime_events
1781
1782              #(#[doc = #docs])*
1783              #[derive(Clone, Debug, PartialEq, Eq)]
1784              #derive_ord
1785              #custom_derive
1786              #[derive(::codec::Encode, ::codec::Decode)]
1787              #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1788              #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1789              pub enum #ty_ident #params {
1790                #variants
1791              }
1792            },
1793            params,
1794          )
1795        }
1796        _ => {
1797          return None;
1798        }
1799      };
1800
1801      let is_error_sub_type = match full_name.as_str() {
1802        "sp_runtime::TokenError" => true,
1803        "sp_runtime::TransactionalError" => true,
1804        "sp_arithmetic::ArithmeticError" => true,
1805        _ => false,
1806      };
1807      // Generate `as_static_str` for some enum types:
1808      // * Pallet types: *Call, *Event, *Error.
1809      // * Runtime types: RuntimeCall, RuntimeEvent.
1810      // * Sub error type: TokenError, TransactionalError, ArithmeticError.
1811      let gen_as_static_str = pallet_name.is_some()
1812        || (is_runtime_type && (ident == "RuntimeCall" || ident == "RuntimeEvent"))
1813        || is_error_sub_type;
1814
1815      if gen_as_static_str {
1816        if let Some(as_static_str) =
1817          self.gen_enum_as_static_str(&ty_ident, &params, ty, pallet_name)
1818        {
1819          code.append_all(as_static_str);
1820        }
1821      }
1822
1823      Some(code)
1824    }
1825
1826    fn generate_types(&self) -> TokenStream {
1827      // Start with empty namespace.
1828      let mut modules = ModuleCode::new("".into());
1829      let runtime_ns = [String::from("runtime")];
1830
1831      for ty in self.md.types.types() {
1832        let ty_id = ty.id();
1833        let ty = ty.ty();
1834        let ty_path = ty.path();
1835        let mut ty_ns = ty_path.namespace();
1836        // Only generate type code for types with namespaces.  Basic rust types like
1837        // `Result` and `Option` have no namespace.
1838        if let Some(ns_top) = ty_ns.first() {
1839          // Don't generate code for external types.
1840          if !self.external_modules.contains(ns_top) {
1841            let (ident, is_runtime_type) = match self.is_runtime_type(ty_path) {
1842              Some(name) => {
1843                ty_ns = &runtime_ns;
1844                (name, true)
1845              }
1846              None => (ty_path.ident().unwrap(), false),
1847            };
1848
1849            if let Some(code) = self.gen_type(ty_id, ty, &ident, is_runtime_type) {
1850              if ty_ns.is_empty() {
1851                // No namespace
1852                modules.add_type(ty_ns, ident, code);
1853              } else {
1854                let old_ns = ty_ns.join("::");
1855                if let Some(new_ns) = self.remap_namespaces.get(&old_ns) {
1856                  let remapped = new_ns
1857                    .split("::")
1858                    .map(|s| s.to_string())
1859                    .collect::<Vec<_>>();
1860                  modules.add_type(&remapped, ident, code);
1861                } else {
1862                  // No remap.
1863                  modules.add_type(ty_ns, ident, code);
1864                }
1865              }
1866            }
1867          }
1868        }
1869      }
1870
1871      modules.gen()
1872    }
1873
1874    pub fn generate(self) -> TokenStream {
1875      let mut call_fields = TokenStream::new();
1876      let mut query_fields = TokenStream::new();
1877      let mut paged_query_fields = TokenStream::new();
1878
1879      // Generate module code.
1880      let modules: Vec<_> = self
1881        .md
1882        .pallets
1883        .iter()
1884        .map(|m| {
1885          let (ident, call_api, query_api, paged_query_api, code) = self.gen_module(m);
1886          call_fields.append_all(quote! {
1887            pub fn #ident(&self) -> api::#ident::#call_api<'api> {
1888              api::#ident::#call_api::from(self.api)
1889            }
1890          });
1891          query_fields.append_all(quote! {
1892            pub fn #ident(&self) -> api::#ident::#query_api<'api> {
1893              api::#ident::#query_api {
1894                api: self.api,
1895                #[cfg(not(feature = "ink"))]
1896                at: self.at,
1897              }
1898            }
1899          });
1900
1901          paged_query_fields.append_all(quote! {
1902            #[cfg(not(feature = "ink"))]
1903            pub fn #ident(&self) -> api::#ident::#paged_query_api<'api> {
1904              api::#ident::#paged_query_api {
1905                api: self.api,
1906                at: self.at,
1907              }
1908            }
1909          });
1910
1911          code
1912        })
1913        .collect();
1914
1915      let types_code = self.generate_types();
1916
1917      let dispatch_info = if self.v2_weights {
1918        quote! { frame_support::dispatch::DispatchInfo }
1919      } else {
1920        quote! { frame_support::weights::DispatchInfo }
1921      };
1922
1923      let call_ty = &self.call;
1924      let event_ty = &self.event;
1925      quote! {
1926        #[allow(dead_code, unused_imports, non_camel_case_types)]
1927        pub mod types {
1928          use super::WrappedCall;
1929          #types_code
1930        }
1931
1932        #[allow(dead_code, unused_imports, non_camel_case_types)]
1933        pub mod api {
1934          use super::types;
1935          use super::types::*;
1936          use super::WrappedCall;
1937
1938          #( #modules )*
1939        }
1940
1941        #[derive(Clone)]
1942        pub struct Api {
1943          #[cfg(not(feature = "ink"))]
1944          client: ::polymesh_api_client::Client,
1945        }
1946
1947        impl Api {
1948          #[cfg(feature = "ink")]
1949          pub fn new() -> Self {
1950            Self {}
1951          }
1952
1953          #[cfg(feature = "ink")]
1954          pub fn runtime(&self) -> ::polymesh_api_ink::extension::PolymeshRuntimeInstance {
1955            ::polymesh_api_ink::extension::new_instance()
1956          }
1957
1958          #[cfg(feature = "ink")]
1959          pub fn read_storage<T: ::codec::Decode>(&self, key: ::alloc::vec::Vec<u8>) -> ::polymesh_api_ink::error::Result<Option<T>> {
1960            let runtime = self.runtime();
1961            let value = runtime.read_storage(key.into())?
1962              .map(|data| T::decode(&mut data.as_slice()))
1963              .transpose()?;
1964            Ok(value)
1965          }
1966
1967          #[cfg(not(feature = "ink"))]
1968          pub async fn new(url: &str) -> ::polymesh_api_client::error::Result<Self> {
1969            Ok(Self {
1970              client: ::polymesh_api_client::Client::new(url).await?
1971            })
1972          }
1973
1974          pub fn call(&self) -> CallApi {
1975            CallApi { api: self }
1976          }
1977
1978          #[cfg(not(feature = "ink"))]
1979          pub fn query(&self) -> QueryApi {
1980            QueryApi { api: self, at: None }
1981          }
1982
1983          #[cfg(feature = "ink")]
1984          pub fn query(&self) -> QueryApi {
1985            QueryApi { api: self }
1986          }
1987
1988          #[cfg(not(feature = "ink"))]
1989          pub fn query_at(&self, block: ::polymesh_api_client::BlockHash) -> QueryApi {
1990            QueryApi { api: self, at: Some(block) }
1991          }
1992
1993          #[cfg(not(feature = "ink"))]
1994          pub fn paged_query(&self) -> PagedQueryApi {
1995            PagedQueryApi { api: self, at: None }
1996          }
1997
1998          #[cfg(not(feature = "ink"))]
1999          pub fn paged_query_at(&self, block: ::polymesh_api_client::BlockHash) -> PagedQueryApi {
2000            PagedQueryApi { api: self, at: Some(block) }
2001          }
2002
2003          #[cfg(not(feature = "ink"))]
2004          pub fn wrap_call(&self, call: types::#call_ty) -> ::polymesh_api_client::Result<WrappedCall> {
2005            Ok(WrappedCall::new(self, call))
2006          }
2007
2008          #[cfg(feature = "ink")]
2009          pub fn wrap_call(&self, call: ::alloc::vec::Vec<u8>) -> WrappedCall {
2010            WrappedCall::new(call)
2011          }
2012        }
2013
2014        #[cfg(not(feature = "ink"))]
2015        use alloc::boxed::Box;
2016        #[async_trait::async_trait]
2017        #[cfg(not(feature = "ink"))]
2018        impl ::polymesh_api_client::ChainApi for Api {
2019          type RuntimeCall = types::#call_ty;
2020          type RuntimeEvent = types::#event_ty;
2021          type DispatchInfo = types::#dispatch_info;
2022          type DispatchError = types::sp_runtime::DispatchError;
2023
2024          async fn get_nonce(&self, account: ::polymesh_api_client::AccountId) -> ::polymesh_api_client::Result<u32> {
2025            let info = self.query().system().account(account).await?;
2026            Ok(info.nonce)
2027          }
2028
2029          async fn block_events(&self, block: Option<::polymesh_api_client::BlockHash>) -> ::polymesh_api_client::Result<::alloc::vec::Vec<::polymesh_api_client::EventRecord<Self::RuntimeEvent>>> {
2030            let system = match block {
2031              Some(block) => self.query_at(block).system(),
2032              None => self.query().system(),
2033            };
2034            Ok(system.events().await?)
2035          }
2036
2037          fn event_to_extrinsic_result(event: &::polymesh_api_client::EventRecord<Self::RuntimeEvent>) -> Option<::polymesh_api_client::ExtrinsicResult<Self>> {
2038            match &event.event {
2039              types::#event_ty::System(types::frame_system::pallet::SystemEvent::ExtrinsicSuccess { dispatch_info }) =>
2040                Some(::polymesh_api_client::ExtrinsicResult::Success(dispatch_info.clone())),
2041              types::#event_ty::System(types::frame_system::pallet::SystemEvent::ExtrinsicFailed { dispatch_info, dispatch_error }) =>
2042                Some(::polymesh_api_client::ExtrinsicResult::Failed(dispatch_info.clone(), dispatch_error.clone())),
2043              _ => None,
2044            }
2045          }
2046
2047          fn client(&self) -> &::polymesh_api_client::Client {
2048            &self.client
2049          }
2050        }
2051
2052        #[derive(Clone)]
2053        pub struct CallApi<'api> {
2054          api: &'api Api,
2055        }
2056
2057        impl<'api> CallApi<'api> {
2058          #call_fields
2059        }
2060
2061        #[cfg(not(feature = "ink"))]
2062        pub type WrappedCall = ::polymesh_api_client::Call<Api>;
2063        #[cfg(not(feature = "ink"))]
2064        pub type TransactionResults = ::polymesh_api_client::TransactionResults<Api>;
2065
2066        #[cfg(feature = "ink")]
2067        pub type WrappedCall = ::polymesh_api_ink::Call;
2068
2069        #[cfg(not(feature = "ink"))]
2070        impl From<WrappedCall> for types::#call_ty {
2071          fn from(wrapped: WrappedCall) -> Self {
2072            wrapped.into_runtime_call()
2073          }
2074        }
2075
2076        #[cfg(not(feature = "ink"))]
2077        impl From<&WrappedCall> for types::#call_ty {
2078          fn from(wrapped: &WrappedCall) -> Self {
2079            wrapped.runtime_call().clone()
2080          }
2081        }
2082
2083        #[derive(Clone)]
2084        pub struct QueryApi<'api> {
2085          api: &'api Api,
2086          #[cfg(not(feature = "ink"))]
2087          at: Option<::polymesh_api_client::BlockHash>,
2088        }
2089
2090        impl<'api> QueryApi<'api> {
2091          #query_fields
2092        }
2093
2094        #[derive(Clone)]
2095        #[cfg(not(feature = "ink"))]
2096        pub struct PagedQueryApi<'api> {
2097          api: &'api Api,
2098          at: Option<::polymesh_api_client::BlockHash>,
2099        }
2100
2101        #[cfg(not(feature = "ink"))]
2102        impl<'api> PagedQueryApi<'api> {
2103          #paged_query_fields
2104        }
2105      }
2106    }
2107  }
2108
2109  pub fn generate(md: RuntimeMetadataV14) -> TokenStream {
2110    Generator::new(md).generate()
2111  }
2112}
2113
2114pub fn generate(metadata: RuntimeMetadataPrefixed) -> Result<TokenStream, String> {
2115  match metadata.1 {
2116    #[cfg(feature = "v14")]
2117    RuntimeMetadata::V14(v14) => Ok(v14::generate(v14)),
2118    _ => {
2119      return Err(format!("Unsupported metadata version"));
2120    }
2121  }
2122}
2123
2124pub fn macro_codegen(mut buf: &[u8], mod_ident: TokenStream) -> Result<TokenStream, String> {
2125  let metadata = RuntimeMetadataPrefixed::decode(&mut buf).map_err(|e| e.to_string())?;
2126
2127  let code = generate(metadata)?;
2128  Ok(quote! {
2129    pub mod #mod_ident {
2130      #code
2131    }
2132  })
2133}