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