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