ink_codegen/generator/
dispatch.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use core::iter;
16
17use derive_more::From;
18use ink_primitives::abi::Abi;
19use ir::{
20    Callable,
21    CallableWithSelector,
22    Constructor,
23    HexLiteral as _,
24    Message,
25};
26use itertools::Itertools;
27use proc_macro2::{
28    Ident,
29    TokenStream as TokenStream2,
30};
31use quote::{
32    format_ident,
33    quote,
34    quote_spanned,
35};
36use syn::spanned::Spanned as _;
37
38use crate::{
39    generator,
40    generator::sol,
41    GenerateCode,
42};
43
44/// A message to be dispatched.
45/// Contains its callable and calculated unique id
46pub struct MessageDispatchable<'a> {
47    message: CallableWithSelector<'a, Message>,
48    id: TokenStream2,
49}
50
51/// A constructor to be dispatched.
52/// Contains its callable and calculated unique id
53pub struct ConstructorDispatchable<'a> {
54    constructor: CallableWithSelector<'a, Constructor>,
55    id: TokenStream2,
56    abi: Abi,
57}
58
59/// Generates code for the message and constructor dispatcher.
60///
61/// This code efficiently selects the dispatched ink! constructor or message
62/// by inspecting the first four bytes (selector) of the given input bytes.
63///
64/// As this happens on every contract execution this code must be highly optimized.
65/// For that purpose a so-called dispatch enum is being generated that has a
66/// specialized `scale::Decode` implementation taking the first four bytes of
67/// the input stream in order to identify the enum variant that it is going to
68/// produce out of the rest of the input buffer.
69///
70/// The rest of the input buffer is then automatically decoded directly into the
71/// expected input types of the respective ink! constructor or message.
72#[derive(From)]
73pub struct Dispatch<'a> {
74    contract: &'a ir::Contract,
75}
76impl_as_ref_for_generator!(Dispatch);
77
78impl GenerateCode for Dispatch<'_> {
79    fn generate_code(&self) -> TokenStream2 {
80        let messages = self.compose_messages_with_ids();
81        let constructors = self.compose_constructors_with_ids();
82
83        let contract_dispatchable_constructor_infos =
84            self.generate_dispatchable_constructor_infos();
85        let contract_dispatchable_messages_infos =
86            self.generate_dispatchable_message_infos();
87        let constructor_decoder_type =
88            self.generate_constructor_decoder_type(&constructors);
89        let message_decoder_type = self.generate_message_decoder_type(&messages);
90        let entry_points = self.generate_entry_points(&constructors, &messages);
91
92        quote! {
93            #contract_dispatchable_constructor_infos
94            #contract_dispatchable_messages_infos
95            #constructor_decoder_type
96            #message_decoder_type
97
98            #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))]
99            mod __do_not_access__ {
100                use super::*;
101                #entry_points
102            }
103        }
104    }
105}
106
107// We arbitrarily use zero as the id for the Solidity ABI encoded constructor.
108// SAFETY: ink! ABI encoded constructors compute their ids as the
109// `u32` representation of their selector, so a collision is unlikely,
110// and it would lead to compilation error anyway.
111const SOL_CTOR_ID: u32 = 0;
112
113impl Dispatch<'_> {
114    /// Returns the index of the ink! message which has a wildcard selector, if existent.
115    fn query_wildcard_message(&self) -> Option<usize> {
116        self.contract
117            .module()
118            .impls()
119            .flat_map(|item_impl| item_impl.iter_messages())
120            .position(|item| item.has_wildcard_selector())
121    }
122
123    /// Returns the index of the ink! constructor which has a wildcard selector, if
124    /// existent.
125    #[cfg_attr(ink_abi = "sol", allow(dead_code))]
126    fn query_wildcard_constructor(&self) -> Option<usize> {
127        self.contract
128            .module()
129            .impls()
130            .flat_map(|item_impl| item_impl.iter_constructors())
131            .position(|item| item.has_wildcard_selector())
132    }
133
134    /// Returns the constructor to use for Solidity ABI encoded instantiation.
135    fn constructor_sol(&self) -> Option<CallableWithSelector<Constructor>> {
136        self.contract
137            .module()
138            .impls()
139            .flat_map(|item_impl| item_impl.iter_constructors())
140            .find_or_first(|constructor| constructor.is_default())
141    }
142
143    /// Puts messages and their calculated selector ids in a single data structure
144    ///
145    /// See [`MessageDispatchable`]
146    fn compose_messages_with_ids(&self) -> Vec<MessageDispatchable> {
147        let storage_ident = self.contract.module().storage().ident();
148        self.contract
149            .module()
150            .impls()
151            .flat_map(|item_impl| {
152                iter::repeat(item_impl.trait_path()).zip(item_impl.iter_messages())
153            })
154            .flat_map(|(trait_path, message)| {
155                let mut message_dispatchables = Vec::new();
156                for_each_abi!(@type |abi| {
157                    match abi {
158                        Abi::Ink => {
159                            let span = message.span();
160                            let id = if let Some(trait_path) = trait_path {
161                                let local_id = message.local_id().hex_padded_suffixed();
162                                quote_spanned!(span=>
163                                    {
164                                        ::core::primitive::u32::from_be_bytes(
165                                            <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
166                                                as #trait_path>::__ink_TraitInfo
167                                                as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
168                                        )
169                                    }
170                                )
171                            } else {
172                                let id = message
173                                    .composed_selector()
174                                    .into_be_u32()
175                                    .hex_padded_suffixed();
176                                quote_spanned!(span=>
177                                    #id
178                                )
179                            };
180                            message_dispatchables.push(MessageDispatchable { message, id });
181                        }
182                        Abi::Sol => {
183                            let id = sol::utils::selector_id(&message);
184                            message_dispatchables.push(MessageDispatchable { message, id });
185                        }
186                    }
187                });
188
189                message_dispatchables
190            })
191            .collect::<Vec<_>>()
192    }
193
194    /// Puts constructors and their calculated selector ids in a single data structure
195    ///
196    /// See [`ConstructorDispatchable`]
197    fn compose_constructors_with_ids(&self) -> Vec<ConstructorDispatchable> {
198        let mut constructor_dispatchables = Vec::new();
199        for_each_abi!(@type |abi| {
200            match abi {
201                Abi::Ink => {
202                    constructor_dispatchables.extend(
203                        self.contract
204                        .module()
205                        .impls()
206                        .flat_map(|item_impl| item_impl.iter_constructors())
207                        .map(|constructor| {
208                            let id = constructor
209                                .composed_selector()
210                                .into_be_u32()
211                                .hex_padded_suffixed();
212                            ConstructorDispatchable {
213                                constructor,
214                                id: quote!( #id ),
215                                abi: Abi::Ink
216                            }
217                        })
218                    );
219                }
220                Abi::Sol => {
221                    // Only one constructor is used for Solidity ABI encoding.
222                    let constructor = self.constructor_sol()
223                        .expect("Expected at least one constructor");
224                    constructor_dispatchables.push(
225                        ConstructorDispatchable {
226                            constructor,
227                            id: quote!( #SOL_CTOR_ID ),
228                            abi: Abi::Sol
229                        }
230                    );
231                }
232            }
233        });
234        constructor_dispatchables
235    }
236
237    /// Generate code for the [`ink::DispatchableConstructorInfo`] trait implementations.
238    ///
239    /// These trait implementations store relevant dispatch information for every
240    /// dispatchable ink! constructor of the ink! smart contract.
241    fn generate_dispatchable_constructor_infos(&self) -> TokenStream2 {
242        generate_abi_impls!(@type |abi| {
243            match abi {
244                Abi::Ink => {
245                    let span = self.contract.module().storage().span();
246                    let constructor_infos = self
247                        .contract
248                        .module()
249                        .impls()
250                        .flat_map(|item_impl| item_impl.iter_constructors())
251                        .map(|constructor| self.generate_dispatchable_constructor_info(constructor, abi));
252                    quote_spanned!(span=>
253                        #( #constructor_infos )*
254                    )
255                }
256                Abi::Sol => {
257                    // Only one constructor is used for Solidity ABI encoding.
258                    let constructor = self.constructor_sol()
259                        .expect("Expected at least one constructor");
260                    self.generate_dispatchable_constructor_info(constructor, abi)
261                }
262            }
263        })
264    }
265
266    /// Generate code for the [`ink::DispatchableConstructorInfo`] trait implementation
267    /// for a single dispatchable ink! constructor of the ink! smart contract.
268    ///
269    /// This trait implementation stores relevant dispatch information for the
270    /// dispatchable ink! constructor for the specified ABI.
271    ///
272    /// # Note
273    ///
274    /// Only one constructor is used for Solidity ABI encoding,
275    /// so generating Solidity ABI encoded constructor info for multiple constructors
276    /// results in a compilation error.
277    fn generate_dispatchable_constructor_info(
278        &self,
279        constructor: CallableWithSelector<Constructor>,
280        abi: Abi,
281    ) -> TokenStream2 {
282        let storage_ident = self.contract.module().storage().ident();
283        let span = constructor.span();
284        let constructor_ident = constructor.ident();
285        let payable = constructor.is_payable();
286        let cfg_attrs = constructor.get_cfg_attrs(span);
287        let output_type = constructor
288            .output()
289            .map(quote::ToTokens::to_token_stream)
290            .unwrap_or_else(|| quote! { () });
291        let input_bindings = generator::input_bindings(constructor.inputs());
292        let input_tuple_type = generator::input_types_tuple(constructor.inputs());
293        let input_tuple_bindings = generator::input_bindings_tuple(constructor.inputs());
294        let constructor_return_type = quote_spanned!(span=>
295            <::ink::reflect::ConstructorOutputValue<#output_type>
296                as ::ink::reflect::ConstructorOutput<#storage_ident>>
297        );
298
299        #[cfg(feature = "std")]
300        let return_type = quote! { () };
301        #[cfg(not(feature = "std"))]
302        let return_type = quote! { ! };
303
304        let (constructor_id, selector_bytes, abi_ty, decode_trait, return_expr) =
305            match abi {
306                Abi::Ink => {
307                    let id = constructor
308                        .composed_selector()
309                        .into_be_u32()
310                        .hex_padded_suffixed();
311                    let selector_bytes = constructor.composed_selector().hex_lits();
312                    (
313                        quote!( #id ),
314                        quote! {
315                            ::core::option::Option::Some([ #( #selector_bytes ),* ])
316                        },
317                        quote!(::ink::abi::Abi::Ink),
318                        quote!(::ink::scale::Decode),
319                        quote_spanned!(span =>
320                            ::ink::env::return_value::<
321                                ::ink::ConstructorResult<
322                                    ::core::result::Result<(), &Self::Error>
323                                >,
324                            >(
325                                flags,
326                                // Currently no `LangError`s are raised at this level of the
327                                // dispatch logic so `Ok` is always returned to the caller.
328                                &::ink::ConstructorResult::Ok(output),
329                            )
330                        ),
331                    )
332                }
333                Abi::Sol => {
334                    // Only one constructor is used for Solidity ABI encoding.
335                    // We always use the same selector id for Solidity constructors.
336                    // Attempting to generate constructor info for multiple constructors
337                    // will thus lead to a compilation error.
338                    let decode_trait = if input_bindings.len() == 1 {
339                        quote!(::ink::SolDecode)
340                    } else {
341                        quote!(::ink::sol::SolParamsDecode)
342                    };
343                    (
344                        quote!( #SOL_CTOR_ID ),
345                        quote!(::core::option::Option::None),
346                        quote!(::ink::abi::Abi::Sol),
347                        decode_trait,
348                        quote_spanned!(span =>
349                            ::ink::env::return_value_solidity::<::core::result::Result<(), &Self::Error>>(
350                                flags,
351                                &output,
352                            )
353                        ),
354                    )
355                }
356            };
357        quote_spanned!(span =>
358            #( #cfg_attrs )*
359            impl ::ink::reflect::DispatchableConstructorInfo<#constructor_id> for #storage_ident {
360                type Input = #input_tuple_type;
361                type Output = #output_type;
362                type Storage = #storage_ident;
363                type Error = #constructor_return_type::Error;
364                const IS_RESULT: ::core::primitive::bool = #constructor_return_type::IS_RESULT;
365
366                const CALLABLE: fn(Self::Input) -> Self::Output = |#input_tuple_bindings| {
367                    #storage_ident::#constructor_ident(#( #input_bindings ),* )
368                };
369                const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
370                    |input| {
371                        <Self::Input as #decode_trait>::decode(input)
372                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
373                    };
374                const RETURN: fn(::ink::env::ReturnFlags, ::core::result::Result<(), &Self::Error>) -> #return_type =
375                        |flags, output| {
376                            #return_expr
377                        };
378                const PAYABLE: ::core::primitive::bool = #payable;
379                const SELECTOR: ::core::option::Option<[::core::primitive::u8; 4usize]> = #selector_bytes;
380                const LABEL: &'static ::core::primitive::str = ::core::stringify!(#constructor_ident);
381                const ABI: ::ink::abi::Abi = #abi_ty;
382            }
383        )
384    }
385
386    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
387    ///
388    /// These trait implementations store relevant dispatch information for every
389    /// dispatchable ink! message of the ink! smart contract.
390    fn generate_dispatchable_message_infos(&self) -> TokenStream2 {
391        let span = self.contract.module().storage().span();
392
393        let inherent_message_infos = self
394            .contract
395            .module()
396            .impls()
397            .filter(|item_impl| item_impl.trait_path().is_none())
398            .flat_map(|item_impl| item_impl.iter_messages())
399            .map(|message| self.dispatchable_inherent_message_infos(&message));
400        let trait_message_infos = self
401            .contract
402            .module()
403            .impls()
404            .filter_map(|item_impl| {
405                item_impl
406                    .trait_path()
407                    .map(|trait_path| {
408                        let trait_ident = item_impl.trait_ident().expect(
409                            "must have an ink! trait identifier if it is an ink! trait implementation"
410                        );
411                        iter::repeat((trait_ident, trait_path)).zip(item_impl.iter_messages())
412                    })
413            })
414            .flatten()
415            .map(|((trait_ident, trait_path), message)| {
416                self.dispatchable_trait_message_infos(&message, trait_ident, trait_path)
417            });
418        quote_spanned!(span=>
419            #( #inherent_message_infos )*
420            #( #trait_message_infos )*
421        )
422    }
423
424    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
425    ///
426    /// These trait implementations store relevant dispatch information for every
427    /// inherent dispatchable ink! message of the ink! smart contract.
428    fn dispatchable_inherent_message_infos(
429        &self,
430        message: &CallableWithSelector<Message>,
431    ) -> TokenStream2 {
432        let storage_ident = self.contract.module().storage().ident();
433
434        let message_span = message.span();
435        let message_ident = message.ident();
436        let payable = message.is_payable();
437        let mutates = message.receiver().is_ref_mut();
438
439        let cfg_attrs = message.get_cfg_attrs(message_span);
440        let output_tuple_type = message
441            .output()
442            .map(quote::ToTokens::to_token_stream)
443            .unwrap_or_else(|| quote! { () });
444        let input_bindings = generator::input_bindings(message.inputs());
445        let input_tuple_type = generator::input_types_tuple(message.inputs());
446        let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
447
448        #[cfg(feature = "std")]
449        let return_type = quote! { () };
450        #[cfg(not(feature = "std"))]
451        let return_type = quote! { ! };
452
453        generate_abi_impls!(@type |abi| {
454            let (selector_id, selector_bytes, abi_ty, decode_trait, return_expr) = match abi {
455                Abi::Ink => {
456                    let selector_id = message
457                        .composed_selector()
458                        .into_be_u32()
459                        .hex_padded_suffixed();
460                    let selector_bytes = message.composed_selector().hex_lits();
461                    (
462                        quote!(#selector_id),
463                        quote!([ #( #selector_bytes ),* ]),
464                        quote!(::ink::abi::Abi::Ink),
465                        quote!(::ink::scale::Decode),
466                        quote! {
467                            ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
468                                flags,
469                                // Currently no `LangError`s are raised at this level of the
470                                // dispatch logic so `Ok` is always returned to the caller.
471                                &::ink::MessageResult::Ok(output),
472                            )
473                        },
474                    )
475                }
476                Abi::Sol => {
477                    let decode_trait = if input_bindings.len() == 1 {
478                        quote!(::ink::SolDecode)
479                    } else {
480                        quote!(::ink::sol::SolParamsDecode)
481                    };
482                    (
483                        sol::utils::selector_id(message),
484                        sol::utils::selector(message),
485                        quote!(::ink::abi::Abi::Sol),
486                        decode_trait,
487                        quote! {
488                            ::ink::env::return_value_solidity::<Self::Output>(
489                                flags,
490                                &output,
491                            )
492                        },
493                    )
494                }
495            };
496            quote_spanned!(message_span=>
497                #( #cfg_attrs )*
498                impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
499                    type Input = #input_tuple_type;
500                    type Output = #output_tuple_type;
501                    type Storage = #storage_ident;
502
503                    const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
504                        |storage, #input_tuple_bindings| {
505                            #storage_ident::#message_ident( storage #( , #input_bindings )* )
506                        };
507                    const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
508                        |input| {
509                            <Self::Input as #decode_trait>::decode(input)
510                                .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
511                        };
512                    const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
513                        |flags, output| {
514                            #return_expr
515                        };
516                    const SELECTOR: [::core::primitive::u8; 4usize] = #selector_bytes;
517                    const PAYABLE: ::core::primitive::bool = #payable;
518                    const MUTATES: ::core::primitive::bool = #mutates;
519                    const LABEL: &'static ::core::primitive::str = ::core::stringify!(#message_ident);
520                    const ABI: ::ink::abi::Abi = #abi_ty;
521                }
522            )
523        })
524    }
525
526    /// Generate code for the [`ink::DispatchableMessageInfo`] trait implementations.
527    ///
528    /// These trait implementations store relevant dispatch information for every
529    /// trait implementation dispatchable ink! message of the ink! smart contract.
530    fn dispatchable_trait_message_infos(
531        &self,
532        message: &CallableWithSelector<Message>,
533        trait_ident: &Ident,
534        trait_path: &syn::Path,
535    ) -> TokenStream2 {
536        let storage_ident = self.contract.module().storage().ident();
537
538        let message_span = message.span();
539        let message_ident = message.ident();
540        let mutates = message.receiver().is_ref_mut();
541        let output_tuple_type = message
542            .output()
543            .map(quote::ToTokens::to_token_stream)
544            .unwrap_or_else(|| quote! { () });
545        let input_bindings = generator::input_bindings(message.inputs());
546        let input_tuple_type = generator::input_types_tuple(message.inputs());
547        let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
548        let label = format!("{trait_ident}::{message_ident}");
549        let cfg_attrs = message.get_cfg_attrs(message_span);
550
551        #[cfg(feature = "std")]
552        let return_type = quote! { () };
553        #[cfg(not(feature = "std"))]
554        let return_type = quote! { ! };
555
556        generate_abi_impls!(@type |abi| {
557            let (local_id, abi_ty, decode_trait, return_expr) = match abi {
558                Abi::Ink => {
559                    let local_id = message.local_id().hex_padded_suffixed();
560                    (
561                        quote!(#local_id),
562                        quote!(::ink::abi::Abi::Ink),
563                        quote!(::ink::scale::Decode),
564                        quote! {
565                            ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
566                                flags,
567                                // Currently no `LangError`s are raised at this level of the
568                                // dispatch logic so `Ok` is always returned to the caller.
569                                &::ink::MessageResult::Ok(output),
570                            )
571                        },
572                    )
573                }
574                Abi::Sol => {
575                    let decode_trait = if input_bindings.len() == 1 {
576                        quote!(::ink::SolDecode)
577                    } else {
578                        quote!(::ink::sol::SolParamsDecode)
579                    };
580                    (
581                        sol::utils::selector_id(message),
582                        quote!(::ink::abi::Abi::Sol),
583                        decode_trait,
584                        quote! {
585                            ::ink::env::return_value_solidity::<Self::Output>(
586                                flags,
587                                &output,
588                            )
589                        },
590                    )
591                }
592            };
593            let payable = quote! {{
594                <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
595                    as #trait_path>::__ink_TraitInfo
596                    as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE
597            }};
598            let selector = quote! {{
599                <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
600                    as #trait_path>::__ink_TraitInfo
601                    as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
602            }};
603            let selector_id = quote! {{
604                ::core::primitive::u32::from_be_bytes(#selector)
605            }};
606            quote_spanned!(message_span=>
607                #( #cfg_attrs )*
608                impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
609                    type Input = #input_tuple_type;
610                    type Output = #output_tuple_type;
611                    type Storage = #storage_ident;
612
613                    const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
614                        |storage, #input_tuple_bindings| {
615                            <#storage_ident as #trait_path>::#message_ident( storage #( , #input_bindings )* )
616                        };
617                    const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
618                        |input| {
619                            <Self::Input as #decode_trait>::decode(input)
620                                .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
621                        };
622                    const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
623                        |flags, output| {
624                            #return_expr
625                        };
626                    const SELECTOR: [::core::primitive::u8; 4usize] = #selector;
627                    const PAYABLE: ::core::primitive::bool = #payable;
628                    const MUTATES: ::core::primitive::bool = #mutates;
629                    const LABEL: &'static ::core::primitive::str = #label;
630                    const ABI: ::ink::abi::Abi = #abi_ty;
631                }
632            )
633        })
634    }
635
636    /// Generates code for the entry points of the root ink! smart contract.
637    ///
638    /// This generates the `deploy` and `call` functions with which the smart
639    /// contract runtime mainly interacts with the ink! smart contract.
640    fn generate_entry_points(
641        &self,
642        constructors: &[ConstructorDispatchable],
643        messages: &[MessageDispatchable],
644    ) -> TokenStream2 {
645        let span = self.contract.module().storage().span();
646        let storage_ident = self.contract.module().storage().ident();
647        let any_constructor_accept_payment =
648            self.any_constructor_accepts_payment(constructors);
649        let any_message_accepts_payment = self.any_message_accepts_payment(messages);
650
651        let fn_call: syn::ItemFn = syn::parse_quote! {
652            #[cfg(target_arch = "riscv64")]
653            #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
654            pub extern "C" fn call() {
655                internal_call()
656            }
657        };
658        let fn_deploy: syn::ItemFn = syn::parse_quote! {
659            #[cfg(target_arch = "riscv64")]
660            #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
661            pub extern "C" fn deploy() {
662                internal_deploy()
663            }
664        };
665        quote_spanned!(span=>
666            #[allow(dead_code)] // clippy throws a false positive otherwise
667            #[allow(clippy::nonminimal_bool)]
668            #[cfg(target_arch = "riscv64")]
669            fn internal_deploy() {
670                if !#any_constructor_accept_payment {
671                    ::ink::codegen::deny_payment()
672                        .unwrap_or_else(|error| ::core::panic!("{}", error))
673                }
674
675                let dispatchable = match ::ink::env::decode_input::<
676                    <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type,
677                >() {
678                    ::core::result::Result::Ok(decoded_dispatchable) => {
679                        decoded_dispatchable
680                    }
681                    ::core::result::Result::Err(_decoding_error) => {
682                        let error = ::ink::ConstructorResult::Err(::ink::LangError::CouldNotReadInput);
683
684                        // At this point we're unable to set the `Ok` variant to be the "real"
685                        // constructor output since we were unable to figure out what the caller wanted
686                        // to dispatch in the first place, so we set it to `()`.
687                        //
688                        // This is okay since we're going to only be encoding the `Err` variant
689                        // into the output buffer anyway.
690                        ::ink::env::return_value::<::ink::ConstructorResult<()>>(
691                            ::ink::env::ReturnFlags::REVERT,
692                            &error,
693                        );
694                    }
695                };
696
697                <<#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type
698                    as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
699                .unwrap_or_else(|error| {
700                    ::core::panic!("dispatching ink! constructor failed: {}", error)
701                })
702            }
703
704            #[allow(dead_code)] // clippy throws a false positive otherwise
705            #[allow(clippy::nonminimal_bool)]
706            #[cfg(target_arch = "riscv64")]
707            fn internal_call() {
708                if !#any_message_accepts_payment {
709                    ::ink::codegen::deny_payment()
710                        .unwrap_or_else(|error| ::core::panic!("{}", error))
711                }
712
713                let dispatchable = match ::ink::env::decode_input::<
714                    <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type,
715                >() {
716                    ::core::result::Result::Ok(decoded_dispatchable) => {
717                        decoded_dispatchable
718                    }
719                    ::core::result::Result::Err(_decoding_error) => {
720                        let error = ::ink::MessageResult::Err(::ink::LangError::CouldNotReadInput);
721
722                        // At this point we're unable to set the `Ok` variant to be the "real"
723                        // message output since we were unable to figure out what the caller wanted
724                        // to dispatch in the first place, so we set it to `()`.
725                        //
726                        // This is okay since we're going to only be encoding the `Err` variant
727                        // into the output buffer anyway.
728                        ::ink::env::return_value::<::ink::MessageResult<()>>(
729                            ::ink::env::ReturnFlags::REVERT,
730                            &error,
731                        );
732                    }
733                };
734
735                <<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
736                    as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
737                .unwrap_or_else(|error| {
738                    ::core::panic!("dispatching ink! message failed: {}", error)
739                })
740            }
741
742            #fn_call
743
744            #fn_deploy
745        )
746    }
747
748    /// Generates code for the ink! constructor decoder type of the ink! smart contract.
749    ///
750    /// This type can be used in order to decode the input bytes received by a call to
751    /// `deploy` into one of the available dispatchable ink! constructors and their
752    /// arguments.
753    fn generate_constructor_decoder_type(
754        &self,
755        constructors: &[ConstructorDispatchable],
756    ) -> TokenStream2 {
757        /// Expands into the token sequence to represent the
758        /// input type of the ink! constructor at the given index.
759        fn expand_constructor_input(
760            span: proc_macro2::Span,
761            storage_ident: &syn::Ident,
762            constructor_id: TokenStream2,
763        ) -> TokenStream2 {
764            quote_spanned!(span=>
765                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #constructor_id >>::Input
766            )
767        }
768
769        /// Returns the n-th ink! constructor identifier for the decoder type.
770        fn constructor_variant_ident(n: usize) -> syn::Ident {
771            format_ident!("Constructor{}", n)
772        }
773
774        let span = self.contract.module().storage().span();
775        let storage_ident = self.contract.module().storage().ident();
776        let constructors_variants =
777            constructors.iter().enumerate().map(|(index, item)| {
778                let constructor_span = item.constructor.span();
779                let constructor_ident = constructor_variant_ident(index);
780                let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
781                let constructor_input = expand_constructor_input(
782                    constructor_span,
783                    storage_ident,
784                    item.id.clone(),
785                );
786                quote_spanned!(constructor_span=>
787                    #( #cfg_attrs )*
788                    #constructor_ident(#constructor_input)
789                )
790            });
791
792        // Returns dispatch decoding logic for Solidity ABI encoded constructor calls.
793        let solidity_constructor_dispatch_decode = || {
794            let solidity_constructor_info = constructors
795                .iter()
796                .enumerate()
797                .find(|(_, item)| matches!(item.abi, Abi::Sol));
798            match solidity_constructor_info {
799                Some((index, item)) => {
800                    let constructor_span = item.constructor.span();
801                    let constructor_ident = constructor_variant_ident(index);
802                    quote_spanned!(constructor_span=>
803                        <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #SOL_CTOR_ID >>::DECODE(input)
804                            .map(Self::#constructor_ident)
805                    )
806                }
807                None => {
808                    quote! {
809                        ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
810                    }
811                }
812            }
813        };
814
815        #[cfg(not(ink_abi = "sol"))]
816        let decode_dispatch = {
817            let constructor_selector =
818                constructors.iter().enumerate().filter_map(|(index, item)| {
819                    if matches!(item.abi, Abi::Sol) {
820                        // The Solidity ABI encoded constructor doesn't have a selector.
821                        return None;
822                    }
823                    let constructor_span = item.constructor.span();
824                    let const_ident = format_ident!("CONSTRUCTOR_{}", index);
825                    let id = item.id.clone();
826                    let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
827                    Some(quote_spanned!(span=>
828                        #( #cfg_attrs )*
829                        const #const_ident: [::core::primitive::u8; 4usize] = <
830                            #storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >
831                        >::SELECTOR.expect("Expected a selector");
832                    ))
833                });
834
835            let constructor_match = constructors.iter()
836                .enumerate()
837                .filter_map(|(index, item)| {
838                    if matches!(item.abi, Abi::Sol) {
839                        // The Solidity ABI encoded constructor doesn't have a selector to match against.
840                        return None;
841                    }
842                    let constructor_span = item.constructor.span();
843                    let constructor_ident = constructor_variant_ident(index);
844                    let const_ident = format_ident!("CONSTRUCTOR_{}", index);
845                    let id = item.id.clone();
846                    let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
847                    Some(quote_spanned!(constructor_span=>
848                        #( #cfg_attrs )*
849                        #const_ident => {
850                            ::core::result::Result::Ok(Self::#constructor_ident(
851                                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::DECODE(input)?
852                            ))
853                        }
854                    ))
855                });
856
857            let wildcard_selector_constructor =
858                self.query_wildcard_constructor().map(|wildcard_index| {
859                    let item = &constructors[wildcard_index];
860                    let constructor_span = item.constructor.span();
861                    let constructor_ident = constructor_variant_ident(wildcard_index);
862                    let constructor_input = expand_constructor_input(
863                        constructor_span,
864                        storage_ident,
865                        item.id.clone(),
866                    );
867                    quote_spanned!(constructor_span=>
868                        <#constructor_input as ::ink::scale::Decode>::decode(input)
869                            .map(Self::#constructor_ident)
870                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
871                    )
872                });
873
874            let (possible_full_input_ref, fallback_match) = if cfg!(ink_abi = "all") {
875                let solidity_constructor = solidity_constructor_dispatch_decode();
876                let try_wildcard_selector_constructor = wildcard_selector_constructor
877                    .map(|wildcard_selector_constructor| {
878                        quote_spanned!(span=>
879                            let wildcard_result = #wildcard_selector_constructor;
880                            if wildcard_result.is_ok() {
881                                return wildcard_result;
882                            }
883                        )
884                    });
885                (
886                    // Keeps a reference to the entire input slice for Solidity ABI
887                    // decoding fallback.
888                    quote_spanned!(span=>
889                        let mut full_input = *input;
890                    ),
891                    quote_spanned!(span=>
892                        {
893                            // Try wildcard constructor (if any).
894                            #try_wildcard_selector_constructor
895
896                            // Fallback to Solidity constructor.
897                            let input = &mut full_input;
898                            #solidity_constructor
899                        }
900                    ),
901                )
902            } else {
903                let fallback_match = wildcard_selector_constructor.unwrap_or_else(|| {
904                    quote_spanned!(span =>
905                        ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
906                    )
907                });
908                (quote!(), fallback_match)
909            };
910
911            quote_spanned!(span =>
912                #possible_full_input_ref
913                #(
914                    #constructor_selector
915                )*
916                match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
917                    .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
918                {
919                    #( #constructor_match , )*
920                    _invalid => #fallback_match
921                }
922            )
923        };
924        #[cfg(ink_abi = "sol")]
925        let decode_dispatch = {
926            let solidity_constructor = solidity_constructor_dispatch_decode();
927            quote_spanned!(span =>
928                #solidity_constructor
929            )
930        };
931
932        let constructor_execute = constructors.iter().enumerate().map(|(index, item)| {
933            let constructor_span = item.constructor.span();
934            let constructor_ident = constructor_variant_ident(index);
935            let id = item.id.clone();
936            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
937            let constructor_callable = quote_spanned!(constructor_span=>
938                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::CALLABLE
939            );
940            let constructor_return = quote_spanned!(constructor_span=>
941                    <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::RETURN
942                );
943            let constructor_output = quote_spanned!(constructor_span=>
944                <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::Output
945            );
946            let deny_payment = quote_spanned!(constructor_span=>
947                !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE
948            );
949            let constructor_value = quote_spanned!(constructor_span=>
950                <::ink::reflect::ConstructorOutputValue<#constructor_output>
951                    as ::ink::reflect::ConstructorOutput::<#storage_ident>>
952            );
953
954            let constructor_accept_payment_assignment =
955                self.any_constructor_accepts_payment(constructors);
956
957            quote_spanned!(constructor_span=>
958                #( #cfg_attrs )*
959                Self::#constructor_ident(input) => {
960                    if #constructor_accept_payment_assignment && #deny_payment {
961                        ::ink::codegen::deny_payment()?;
962                    }
963
964                    let result: #constructor_output = #constructor_callable(input);
965                    let output_value = ::ink::reflect::ConstructorOutputValue::new(result);
966                    let output_result = #constructor_value::as_result(&output_value);
967
968                    if let ::core::result::Result::Ok(contract) = output_result.as_ref() {
969                        ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
970                            &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
971                            contract,
972                        );
973                    }
974
975                    // NOTE: we can't use an if/else expression here
976                    // It fails inside quote_spanned! macro.
977                    // See https://github.com/rust-lang/rust-clippy/issues/6249
978                    let mut flag = ::ink::env::ReturnFlags::empty();
979                    if output_result.is_err() {
980                        flag = ::ink::env::ReturnFlags::REVERT;
981                    }
982
983                    // Constructors don't return arbitrary data,
984                    // so the return type is represented as `Result<(), Error>`
985                    // where `Error = ()` for infallible constructors.
986                    // For Solidity ABI, `Error` is encoded as revert error data.
987                    #constructor_return(flag, output_result.map(|_| ()));
988
989                    #[cfg(feature = "std")]
990                    return ::core::result::Result::Ok(());
991
992                    #[cfg(not(feature = "std"))]
993                    #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
994                    {
995                        ::core::unreachable!("either `return_value` or the `return` before will already have returned");
996                    }
997                }
998            )
999        });
1000        quote_spanned!(span=>
1001            const _: () = {
1002                #[allow(non_camel_case_types)]
1003                pub enum __ink_ConstructorDecoder {
1004                    #( #constructors_variants ),*
1005                }
1006
1007                impl ::ink::env::DecodeDispatch for __ink_ConstructorDecoder {
1008                    fn decode_dispatch(input: &mut &[::core::primitive::u8])
1009                        -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1010                        #decode_dispatch
1011                    }
1012                }
1013
1014                impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder {
1015                    #[allow(clippy::nonminimal_bool, dead_code)]
1016                    fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1017                        match self {
1018                            #( #constructor_execute ),*
1019                        }
1020                    }
1021                }
1022
1023                impl ::ink::reflect::ContractConstructorDecoder for #storage_ident {
1024                    type Type = __ink_ConstructorDecoder;
1025                }
1026            };
1027        )
1028    }
1029
1030    /// Generates code for the ink! message decoder type of the ink! smart contract.
1031    ///
1032    /// This type can be used in order to decode the input bytes received by a call to
1033    /// `call` into one of the available dispatchable ink! messages and their
1034    /// arguments.
1035    fn generate_message_decoder_type(
1036        &self,
1037        messages: &[MessageDispatchable],
1038    ) -> TokenStream2 {
1039        /// Expands into the token sequence to represent the
1040        /// input type of the ink! message at the given index.
1041        fn expand_message_input(
1042            span: proc_macro2::Span,
1043            storage_ident: &Ident,
1044            message_id: TokenStream2,
1045        ) -> TokenStream2 {
1046            quote_spanned!(span=>
1047                <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #message_id >>::Input
1048            )
1049        }
1050
1051        /// Returns the n-th ink! message identifier for the decoder type.
1052        fn message_variant_ident(n: usize) -> syn::Ident {
1053            format_ident!("Message{}", n)
1054        }
1055
1056        let span = self.contract.module().storage().span();
1057        let storage_ident = self.contract.module().storage().ident();
1058        let message_variants = messages.iter().enumerate().map(|(index, item)| {
1059            let message_span = item.message.span();
1060            let message_ident = message_variant_ident(index);
1061            let cfg_attrs = item.message.get_cfg_attrs(message_span);
1062            let message_input =
1063                expand_message_input(message_span, storage_ident, item.id.clone());
1064            quote_spanned!(message_span=>
1065                #( #cfg_attrs )*
1066                #message_ident(#message_input)
1067            )
1068        });
1069
1070        let message_selector = messages
1071            .iter()
1072            .enumerate()
1073            .map(|(index, item)|  {
1074                let message_span = item.message.span();
1075                let const_ident = format_ident!("MESSAGE_{}", index);
1076                let cfg_attrs = item.message.get_cfg_attrs(message_span);
1077                let id = item.id.clone();
1078                quote_spanned!(span=>
1079                    #( #cfg_attrs )*
1080                    const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::SELECTOR;
1081                )
1082        });
1083
1084        let message_match =  messages
1085            .iter()
1086            .enumerate()
1087            .map(|(index, item)| {
1088                let message_ident = message_variant_ident(index);
1089                let const_ident = format_ident!("MESSAGE_{}", index);
1090                let message_span = item.message.span();
1091                let cfg_attrs = item.message.get_cfg_attrs(message_span);
1092                let id = item.id.clone();
1093                quote_spanned!(message_span=>
1094                   #( #cfg_attrs )*
1095                    #const_ident => {
1096                        ::core::result::Result::Ok(Self::#message_ident(
1097                            <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::DECODE(input)?
1098                        ))
1099                    }
1100                )
1101        });
1102        let possibly_wildcard_selector_message = match self.query_wildcard_message() {
1103            Some(wildcard_index) => {
1104                let item = messages
1105                    .get(wildcard_index)
1106                    .expect("unable to get wildcard index");
1107                let message_span = item.message.span();
1108                let message_ident = message_variant_ident(wildcard_index);
1109                let message_input =
1110                    expand_message_input(message_span, storage_ident, item.id.clone());
1111                quote! {
1112                    ::core::result::Result::Ok(Self::#message_ident(
1113                        <#message_input as ::ink::scale::Decode>::decode(input)
1114                            .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
1115                    ))
1116                }
1117            }
1118            None => {
1119                quote! {
1120                    ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
1121                }
1122            }
1123        };
1124
1125        let message_execute = messages
1126            .iter()
1127            .enumerate()
1128            .map(|(index, item)| {
1129                let message_span = item.message.span();
1130                let message_ident = message_variant_ident(index);
1131                let id = item.id.clone();
1132                let cfg_attrs = item.message.get_cfg_attrs(message_span);
1133                let message_callable = quote_spanned!(message_span=>
1134                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::CALLABLE
1135                );
1136                let message_return = quote_spanned!(message_span=>
1137                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::RETURN
1138                );
1139                let message_output = quote_spanned!(message_span=>
1140                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::Output
1141                );
1142                let deny_payment = quote_spanned!(message_span=>
1143                    !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE
1144                );
1145                let mutates_storage = quote_spanned!(message_span=>
1146                    <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::MUTATES
1147                );
1148
1149                let any_message_accepts_payment =
1150                    self.any_message_accepts_payment(messages);
1151
1152                quote_spanned!(message_span=>
1153                    #( #cfg_attrs )*
1154                    Self::#message_ident(input) => {
1155                        if #any_message_accepts_payment && #deny_payment {
1156                            ::ink::codegen::deny_payment()?;
1157                        }
1158
1159                        let result: #message_output = #message_callable(&mut contract, input);
1160                        let is_reverted = ::ink::is_result_type!(#message_output)
1161                            && ::ink::is_result_err!(result);
1162
1163                        // NOTE: we can't use an if/else expression here
1164                        // It fails inside quote_spanned! macro.
1165                        // See https://github.com/rust-lang/rust-clippy/issues/6249
1166                        let mut flag = ::ink::env::ReturnFlags::REVERT;
1167
1168                        // no need to push back results: transaction gets reverted anyway
1169                        if !is_reverted {
1170                            flag = ::ink::env::ReturnFlags::empty();
1171                            push_contract(contract, #mutates_storage);
1172                        }
1173
1174                        #message_return(flag, result);
1175
1176                        #[cfg(feature = "std")]
1177                        return ::core::result::Result::Ok(());
1178
1179                        #[cfg(not(feature = "std"))]
1180                        #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
1181                        {
1182                            ::core::unreachable!("either `return_value` or the `return` before will already have returned");
1183                        }
1184                    }
1185                )
1186        });
1187
1188        quote_spanned!(span=>
1189            const _: () = {
1190                #[allow(non_camel_case_types)]
1191                pub enum __ink_MessageDecoder {
1192                    #( #message_variants ),*
1193                }
1194
1195                impl ::ink::env::DecodeDispatch for __ink_MessageDecoder {
1196                    fn decode_dispatch(input: &mut &[::core::primitive::u8])
1197                        -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1198                        #(
1199                            #message_selector
1200                        )*
1201                        match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
1202                            .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
1203                        {
1204                            #( #message_match , )*
1205                            _invalid => #possibly_wildcard_selector_message
1206                        }
1207                    }
1208                }
1209
1210                fn push_contract(contract: ::core::mem::ManuallyDrop<#storage_ident>, mutates: bool) {
1211                    if mutates {
1212                        ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
1213                            &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
1214                            &contract,
1215                        );
1216                    }
1217                }
1218
1219                impl ::ink::reflect::ExecuteDispatchable for __ink_MessageDecoder {
1220                    #[allow(clippy::nonminimal_bool, clippy::let_unit_value, dead_code)]
1221                    fn execute_dispatchable(
1222                        self
1223                    ) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1224                        let key = <#storage_ident as ::ink::storage::traits::StorageKey>::KEY;
1225                        let mut contract: ::core::mem::ManuallyDrop<#storage_ident> =
1226                            ::core::mem::ManuallyDrop::new(
1227                                match ::ink::env::get_contract_storage(&key) {
1228                                    ::core::result::Result::Ok(::core::option::Option::Some(value)) => value,
1229                                    ::core::result::Result::Ok(::core::option::Option::None) => {
1230                                        ::core::panic!("storage entry was empty")
1231                                    },
1232                                    ::core::result::Result::Err(_) => {
1233                                        ::core::panic!("could not properly decode storage entry")
1234                                    },
1235                                }
1236                            );
1237
1238                        match self {
1239                            #( #message_execute ),*
1240                        }
1241                    }
1242                }
1243
1244                impl ::ink::reflect::ContractMessageDecoder for #storage_ident {
1245                    type Type = __ink_MessageDecoder;
1246                }
1247            };
1248        )
1249    }
1250
1251    /// Generates code to express if any dispatchable ink! message accepts payment.
1252    ///
1253    /// Generates code in the form of variable assignments
1254    /// which can be conditionally omitted
1255    /// in which case the default assignment `let message_{id} = false` exists.
1256    ///
1257    /// This information can be used to speed-up dispatch since denying of payment
1258    /// can be generalized to work before dispatch happens if none of the ink! messages
1259    /// accept payment anyways.
1260    fn any_message_accepts_payment(
1261        &self,
1262        messages: &[MessageDispatchable],
1263    ) -> TokenStream2 {
1264        let span = self.contract.module().storage().span();
1265        let storage_ident = self.contract.module().storage().ident();
1266        let message_is_payable =  messages
1267            .iter()
1268            .enumerate()
1269            .map(|(index, item)| {
1270            let message_span = item.message.span();
1271            let cfg_attrs = item.message.get_cfg_attrs(message_span);
1272            let id = item.id.clone();
1273            let ident = quote::format_ident!("message_{}", index);
1274            quote_spanned!(message_span=>
1275                {
1276                    let #ident = false;
1277                    #( #cfg_attrs )*
1278                    let #ident = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE;
1279                    #ident
1280                }
1281            )
1282        });
1283        quote_spanned!(span=>
1284            {
1285                false #( || #message_is_payable )*
1286            }
1287        )
1288    }
1289
1290    /// Generates code to express if any dispatchable ink! constructor accepts payment.
1291    ///
1292    /// Generates code in the form of variable assignments
1293    /// which can be conditionally omitted
1294    /// in which case the default assignment `let constructor_{id} = false` exists.
1295    ///
1296    /// This information can be used to speed-up dispatch since denying of payment
1297    /// can be generalized to work before dispatch happens if none of the ink!
1298    /// constructors accept payment anyways.
1299    fn any_constructor_accepts_payment(
1300        &self,
1301        constructors: &[ConstructorDispatchable],
1302    ) -> TokenStream2 {
1303        let span = self.contract.module().storage().span();
1304        let storage_ident = self.contract.module().storage().ident();
1305        let constructor_is_payable = constructors.iter().enumerate().map(|(index, item)| {
1306            let constructor_span = item.constructor.span();
1307            let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
1308            let id = item.id.clone();
1309            let ident = quote::format_ident!("constructor_{}", index);
1310            quote_spanned!(constructor_span=>
1311                {
1312                    let #ident = false;
1313                    #( #cfg_attrs )*
1314                    let #ident = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE;
1315                    #ident
1316                }
1317            )
1318        });
1319        quote_spanned!(span=>
1320            {
1321                false #( || #constructor_is_payable )*
1322            }
1323        )
1324    }
1325}