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 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 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 ("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 ("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 ("PortfolioId", &ink_enum_derives),
340 ("PortfolioKind", &ink_enum_derives),
341 ("PortfolioNumber", &ink_id_derives),
342 ("MovePortfolioItem", &ink_derives),
343 ("Memo", &ink_derives),
344 ("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 ("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 gen.remap_namespaces();
386
387 gen.ord_types.insert("Ticker".into());
389 let mut ord_type_ids = BTreeSet::new();
391 for _ in 0..10 {
392 if !gen.check_for_ord_types(&mut ord_type_ids) {
393 break;
395 }
396 }
397 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 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 segments.pop();
445
446 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 let new_name = format!("{}{}", p_name, kind);
454 segments.push(new_name.clone());
455
456 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 fn rename_pallet_types(&mut self) {
464 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 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 match full_name.as_str() {
521 "BTreeSet" | "BTreeMap" => {
522 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 if ord_type_ids.contains(&id) {
535 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 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 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 (vec![(key, hasher)], value.id())
748 }
749 hashers => {
750 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 (vec![(key, hasher)], value.id())
890 }
891 hashers => {
892 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 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 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 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 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 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 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 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 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 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 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, ¶ms, 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 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 if let Some(ns_top) = ty_ns.first() {
1839 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 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 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 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}