sylvia_derive/contract/
mt.rs

1use convert_case::Case;
2use proc_macro2::{Ident, TokenStream};
3use quote::quote;
4use syn::{parse_quote, GenericParam, ItemImpl, Type};
5
6use crate::crate_module;
7use crate::parser::attributes::features::SylviaFeatures;
8use crate::parser::attributes::msg::MsgType;
9use crate::parser::variant_descs::AsVariantDescs;
10use crate::parser::{
11    Custom, FilteredOverrideEntryPoints, OverrideEntryPoint, ParsedSylviaAttributes,
12};
13use crate::types::msg_variant::{MsgVariant, MsgVariants};
14use crate::utils::{emit_bracketed_generics, get_ident_from_type, SvCasing};
15
16/// Emits helpers for testing contract messages using MultiTest.
17///
18/// More info here: [MultiTest helpers](https://cosmwasm-docs.vercel.app/sylvia/macros/generated-types/multitest).
19pub struct MtHelpers<'a> {
20    error_type: Type,
21    contract_name: &'a Type,
22    source: &'a ItemImpl,
23    generic_params: &'a [&'a GenericParam],
24    where_clause: &'a Option<syn::WhereClause>,
25    custom: &'a Custom,
26    override_entry_points: Vec<OverrideEntryPoint>,
27    sv_features: SylviaFeatures,
28    instantiate_variant: MsgVariants<'a, GenericParam>,
29    exec_variants: MsgVariants<'a, GenericParam>,
30    query_variants: MsgVariants<'a, GenericParam>,
31    migrate_variants: MsgVariants<'a, GenericParam>,
32    reply_variants: MsgVariants<'a, GenericParam>,
33    sudo_variants: MsgVariants<'a, GenericParam>,
34}
35
36impl<'a> MtHelpers<'a> {
37    pub fn new(
38        source: &'a ItemImpl,
39        generic_params: &'a [&'a GenericParam],
40        custom: &'a Custom,
41        override_entry_points: Vec<OverrideEntryPoint>,
42    ) -> Self {
43        let where_clause = &source.generics.where_clause;
44        let instantiate_variant = MsgVariants::new(
45            source.as_variants(),
46            MsgType::Instantiate,
47            generic_params,
48            where_clause,
49        );
50        let exec_variants = MsgVariants::new(
51            source.as_variants(),
52            MsgType::Exec,
53            generic_params,
54            where_clause,
55        );
56        let query_variants = MsgVariants::new(
57            source.as_variants(),
58            MsgType::Query,
59            generic_params,
60            where_clause,
61        );
62        let migrate_variants = MsgVariants::new(
63            source.as_variants(),
64            MsgType::Migrate,
65            generic_params,
66            where_clause,
67        );
68        let reply_variants = MsgVariants::new(
69            source.as_variants(),
70            MsgType::Reply,
71            generic_params,
72            where_clause,
73        );
74        let sudo_variants = MsgVariants::new(
75            source.as_variants(),
76            MsgType::Sudo,
77            generic_params,
78            where_clause,
79        );
80
81        let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
82        let error_type = parsed_attrs.error_attrs.unwrap_or_default().error;
83        let error_type = parse_quote! { #error_type };
84        let sv_features = parsed_attrs.sv_features;
85
86        let contract_name = &source.self_ty;
87
88        Self {
89            error_type,
90            source,
91            generic_params,
92            where_clause,
93            contract_name,
94            custom,
95            override_entry_points,
96            sv_features,
97            instantiate_variant,
98            exec_variants,
99            query_variants,
100            sudo_variants,
101            migrate_variants,
102            reply_variants,
103        }
104    }
105
106    pub fn emit(&self) -> TokenStream {
107        let Self {
108            error_type,
109            contract_name,
110            custom,
111            exec_variants,
112            query_variants,
113            migrate_variants,
114            sudo_variants,
115            generic_params,
116            where_clause,
117            ..
118        } = self;
119        let sylvia = crate_module();
120
121        let custom_msg = custom.msg_or_default();
122        let mt_app: Type = parse_quote! {
123            #sylvia ::cw_multi_test::App<
124                BankT,
125                ApiT,
126                StorageT,
127                CustomT,
128                WasmT,
129                StakingT,
130                DistrT,
131                IbcT,
132                GovT,
133            >
134        };
135        let api = quote! { < #contract_name as #sylvia ::types::ContractApi> };
136
137        let contract_ident = get_ident_from_type(contract_name);
138        let contract: Type = if !generic_params.is_empty() {
139            parse_quote! { #contract_ident ::< #(#generic_params,)* > }
140        } else {
141            parse_quote! { #contract_ident }
142        };
143        let trait_name = Ident::new(&format!("{}Proxy", contract_ident), contract_ident.span());
144
145        let exec_methods = exec_variants.variants().map(|variant| {
146            variant.emit_mt_method_definition(&custom_msg, &mt_app, error_type, &api)
147        });
148        let query_methods = query_variants.variants().map(|variant| {
149            variant.emit_mt_method_definition(&custom_msg, &mt_app, error_type, &api)
150        });
151        let sudo_methods = sudo_variants.variants().map(|variant| {
152            variant.emit_mt_method_definition(&custom_msg, &mt_app, error_type, &api)
153        });
154        let migrate_methods = migrate_variants.variants().map(|variant| {
155            variant.emit_mt_method_definition(&custom_msg, &mt_app, error_type, &api)
156        });
157
158        let exec_methods_declarations = exec_variants
159            .variants()
160            .map(|variant| variant.emit_mt_method_declaration(&custom_msg, error_type, &api));
161        let query_methods_declarations = query_variants
162            .variants()
163            .map(|variant| variant.emit_mt_method_declaration(&custom_msg, error_type, &api));
164        let sudo_methods_declarations = sudo_variants
165            .variants()
166            .map(|variant| variant.emit_mt_method_declaration(&custom_msg, error_type, &api));
167        let migrate_methods_declarations = migrate_variants
168            .variants()
169            .map(|variant| variant.emit_mt_method_declaration(&custom_msg, error_type, &api));
170
171        let where_predicates = where_clause
172            .as_ref()
173            .map(|where_clause| &where_clause.predicates);
174
175        let impl_contract = self.emit_impl_contract();
176        let code_id = self.emit_code_id();
177        let instantiate_proxy = self.emit_instantiate_proxy(&contract);
178
179        quote! {
180            pub mod mt {
181                use super::*;
182                use #sylvia ::cw_multi_test::Executor;
183
184                pub trait #trait_name <'app, #(#generic_params,)* MtApp >
185                    #where_clause
186                {
187                    #( #exec_methods_declarations )*
188                    #( #migrate_methods_declarations )*
189                    #( #query_methods_declarations )*
190                    #( #sudo_methods_declarations )*
191                }
192
193                impl<'app, #(#generic_params,)* BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT >
194                    #trait_name <'app, #(#generic_params,)* #mt_app >
195                        for #sylvia ::multitest::Proxy <'app, #mt_app, #contract_name >
196                    where
197                        CustomT: #sylvia ::cw_multi_test::Module,
198                        CustomT::ExecT: #sylvia::types::CustomMsg + 'static,
199                        CustomT::QueryT: #sylvia ::types::CustomQuery + 'static,
200                        WasmT: #sylvia ::cw_multi_test::Wasm<CustomT::ExecT, CustomT::QueryT>,
201                        BankT: #sylvia ::cw_multi_test::Bank,
202                        ApiT: #sylvia ::cw_std::Api,
203                        StorageT: #sylvia ::cw_std::Storage,
204                        StakingT: #sylvia ::cw_multi_test::Staking,
205                        DistrT: #sylvia ::cw_multi_test::Distribution,
206                        IbcT: #sylvia ::cw_multi_test::Ibc,
207                        GovT: #sylvia ::cw_multi_test::Gov,
208                        #mt_app : Executor< #custom_msg >,
209                        #where_predicates
210                {
211                    #( #exec_methods )*
212                    #( #migrate_methods )*
213                    #( #query_methods )*
214                    #( #sudo_methods )*
215                }
216
217                #impl_contract
218
219                #code_id
220
221                #instantiate_proxy
222            }
223        }
224    }
225
226    fn emit_code_id(&self) -> TokenStream {
227        let sylvia = crate_module();
228        let Self {
229            generic_params,
230            where_clause,
231            contract_name,
232            instantiate_variant,
233            ..
234        } = self;
235
236        let generic_params_lifetimes_replaced =
237            generic_params.iter().cloned().cloned().map(|generic| {
238                if let GenericParam::Lifetime(_) = generic {
239                    parse_quote! { '_ }
240                } else {
241                    generic
242                }
243            });
244
245        let fields_names = instantiate_variant
246            .get_only_variant()
247            .map(MsgVariant::as_fields_names)
248            .unwrap_or(vec![]);
249
250        let fields = instantiate_variant
251            .get_only_variant()
252            .map(MsgVariant::emit_method_field)
253            .unwrap_or(vec![]);
254
255        let used_generics = instantiate_variant.used_generics();
256
257        let where_predicates = where_clause
258            .as_ref()
259            .map(|where_clause| &where_clause.predicates);
260
261        let contract_ident = get_ident_from_type(contract_name);
262        let contract = if !generic_params.is_empty() {
263            quote! { #contract_ident ::< #(#generic_params,)* > }
264        } else {
265            quote! { #contract_ident }
266        };
267
268        let instantiate_msg = if !used_generics.is_empty() {
269            quote! { InstantiateMsg::< #(#used_generics,)* > }
270        } else {
271            quote! { InstantiateMsg }
272        };
273
274        let custom_msg = self.custom.msg_or_default();
275        let custom_query = self.custom.query_or_default();
276
277        let mt_app = quote! {
278            #sylvia ::cw_multi_test::App<
279                BankT,
280                ApiT,
281                StorageT,
282                CustomT,
283                #sylvia ::cw_multi_test::WasmKeeper< #custom_msg , #custom_query >,
284                StakingT,
285                DistrT,
286                IbcT,
287                GovT,
288            >
289        };
290
291        let code_info = if cfg!(feature = "cosmwasm_1_2") {
292            quote! {
293                pub fn code_info(&self) -> #sylvia ::cw_std::StdResult< #sylvia ::cw_std::CodeInfoResponse> {
294                    self.app.querier().query_wasm_code_info(self.code_id)
295                }
296            }
297        } else {
298            quote! {}
299        };
300
301        quote! {
302            pub struct CodeId<'app, Contract, MtApp> {
303                code_id: u64,
304                app: &'app #sylvia ::multitest::App<MtApp>,
305                _phantom: std::marker::PhantomData<Contract>,
306
307            }
308
309            impl<'app, #(#generic_params,)* BankT, ApiT, StorageT, CustomT, StakingT, DistrT, IbcT, GovT > CodeId<'app, #contract, #mt_app >
310                where
311                    BankT: #sylvia ::cw_multi_test::Bank,
312                    ApiT: #sylvia ::cw_std::Api,
313                    StorageT: #sylvia ::cw_std::Storage,
314                    CustomT: #sylvia ::cw_multi_test::Module<ExecT = #custom_msg, QueryT = #custom_query >,
315                    StakingT: #sylvia ::cw_multi_test::Staking,
316                    DistrT: #sylvia ::cw_multi_test::Distribution,
317                    IbcT: #sylvia ::cw_multi_test::Ibc,
318                    GovT: #sylvia ::cw_multi_test::Gov,
319                    #where_predicates
320            {
321                pub fn store_code(app: &'app #sylvia ::multitest::App< #mt_app >) -> Self {
322                    let code_id = app
323                        .app_mut()
324                        .store_code(Box::new( #contract_ident:: < #(#generic_params_lifetimes_replaced),* > ::new() ));
325                    Self { code_id, app, _phantom: std::marker::PhantomData::default() }
326                }
327
328                pub fn code_id(&self) -> u64 {
329                    self.code_id
330                }
331
332                #code_info
333
334                pub fn instantiate(
335                    &self, #(#fields,)*
336                ) -> InstantiateProxy<'_, 'app, #(#generic_params,)* #mt_app > {
337                    let msg = #instantiate_msg {#(#fields_names,)*};
338                    InstantiateProxy::<'_, 'app, #(#generic_params,)* _> {
339                        code_id: self,
340                        funds: &[],
341                        label: "Contract",
342                        admin: None,
343                        salt: None,
344                        msg,
345                    }
346                }
347            }
348        }
349    }
350
351    fn emit_instantiate_proxy(&self, contract: &Type) -> TokenStream {
352        let sylvia = crate_module();
353        let Self {
354            error_type,
355            generic_params,
356            where_clause,
357            contract_name,
358            instantiate_variant,
359            ..
360        } = self;
361
362        let used_generics = instantiate_variant.used_generics();
363        let bracketed_used_generics = emit_bracketed_generics(used_generics);
364
365        let where_predicates = where_clause
366            .as_ref()
367            .map(|where_clause| &where_clause.predicates);
368
369        let custom_msg = self.custom.msg_or_default();
370
371        let instantiate2_body = self.emit_instantiate2_body();
372
373        quote! {
374            pub struct InstantiateProxy<'proxy, 'app, #(#generic_params,)* MtApp> {
375                code_id: &'proxy CodeId <'app, #contract, MtApp>,
376                funds: &'proxy [#sylvia ::cw_std::Coin],
377                label: &'proxy str,
378                admin: Option<String>,
379                salt: Option<&'proxy [u8]>,
380                msg: InstantiateMsg #bracketed_used_generics,
381            }
382
383            impl<'proxy, 'app, #(#generic_params,)* MtApp> InstantiateProxy<'proxy, 'app, #(#generic_params,)* MtApp>
384                where
385                    MtApp: Executor< #custom_msg >,
386                    #where_predicates
387            {
388                pub fn with_funds(self, funds: &'proxy [#sylvia ::cw_std::Coin]) -> Self {
389                    Self { funds, ..self }
390                }
391
392                pub fn with_label(self, label: &'proxy str) -> Self {
393                    Self { label, ..self }
394                }
395
396                pub fn with_admin<'sv_admins_lifetime>(self, admin: impl Into<Option<&'sv_admins_lifetime str>>) -> Self {
397                    let admin = admin.into().map(str::to_owned);
398                    Self { admin, ..self }
399                }
400
401                pub fn with_salt(self, salt: impl Into<Option<&'proxy [u8]>>) -> Self {
402                    let salt = salt.into();
403                    Self { salt, ..self }
404                }
405
406                #[track_caller]
407                pub fn call(self, sender: &#sylvia ::cw_std::Addr ) -> Result<#sylvia ::multitest::Proxy<'app, MtApp, #contract_name >, #error_type> {
408                    let Self {code_id, funds, label, admin, salt, msg} = self;
409
410                    match salt {
411                        Some(salt) => {
412                            #instantiate2_body
413                        },
414                        None => (*code_id.app)
415                            .app_mut()
416                            .instantiate_contract(
417                                code_id.code_id,
418                                sender.clone(),
419                                &msg,
420                                funds,
421                                label,
422                                admin,
423                            )
424                            .map_err(|err| err.downcast().unwrap())
425                            .map(|addr| #sylvia ::multitest::Proxy {
426                                contract_addr: addr,
427                                app: code_id.app,
428                                _phantom: std::marker::PhantomData::default(),
429                            }),
430                    }
431                }
432            }
433        }
434    }
435
436    fn emit_instantiate2_body(&self) -> TokenStream {
437        let Self { error_type, .. } = self;
438        let sylvia = crate_module();
439
440        if cfg!(feature = "cosmwasm_1_2") {
441            quote! {
442                let msg = #sylvia ::cw_std::to_json_binary(&msg)
443                    .map_err(Into::< #error_type >::into)?;
444                let sender = #sylvia ::cw_std::Addr::unchecked(sender);
445
446                let msg = #sylvia ::cw_std::WasmMsg::Instantiate2 {
447                    admin,
448                    code_id: code_id.code_id,
449                    msg,
450                    funds: funds.to_owned(),
451                    label: label.to_owned(),
452                    salt: salt.into(),
453                };
454                let app_response = (*code_id.app)
455                    .app_mut()
456                    .execute(sender.clone(), msg.into())
457                    .map_err(|err| err.downcast::< #error_type >().unwrap())?;
458
459                #sylvia:: cw_utils::parse_instantiate_response_data(app_response.data.unwrap().as_slice())
460                    .map_err(|err| Into::into( #sylvia ::cw_std::StdError::generic_err(err.to_string())))
461                    .map(|data| #sylvia ::multitest::Proxy {
462                        contract_addr: #sylvia ::cw_std::Addr::unchecked(data.contract_address),
463                        app: code_id.app,
464                        _phantom: std::marker::PhantomData::default(),
465                    })
466            }
467        } else {
468            quote! {
469                let err = #sylvia ::cw_std::StdError::generic_err(
470                    "`with_salt` was called, but it requires `cosmwasm_1_2` feature enabled. Consider removing `with_salt` or adding the `cosmwasm_1_2` feature."
471                );
472                Err(Into::into(err))
473            }
474        }
475    }
476
477    fn emit_impl_contract(&self) -> TokenStream {
478        let Self {
479            source,
480            contract_name,
481            custom,
482            override_entry_points,
483            sv_features,
484            generic_params,
485            migrate_variants,
486            reply_variants,
487            ..
488        } = self;
489        let sylvia = crate_module();
490
491        let bracketed_generics = emit_bracketed_generics(generic_params);
492        let full_where_clause = &source.generics.where_clause;
493
494        let instantiate_body = override_entry_points
495            .get_entry_point(MsgType::Instantiate)
496            .map(OverrideEntryPoint::emit_multitest_dispatch)
497            .unwrap_or_else(|| emit_default_dispatch(&MsgType::Instantiate, contract_name));
498
499        let exec_body = override_entry_points
500            .get_entry_point(MsgType::Exec)
501            .map(OverrideEntryPoint::emit_multitest_dispatch)
502            .unwrap_or_else(|| emit_default_dispatch(&MsgType::Exec, contract_name));
503
504        let query_body = override_entry_points
505            .get_entry_point(MsgType::Query)
506            .map(OverrideEntryPoint::emit_multitest_dispatch)
507            .unwrap_or_else(|| emit_default_dispatch(&MsgType::Query, contract_name));
508
509        let sudo_body = override_entry_points
510            .get_entry_point(MsgType::Sudo)
511            .map(OverrideEntryPoint::emit_multitest_dispatch)
512            .unwrap_or_else(|| emit_default_dispatch(&MsgType::Sudo, contract_name));
513
514        let migrate_body = match override_entry_points.get_entry_point(MsgType::Migrate) {
515            Some(entry_point) => entry_point.emit_multitest_dispatch(),
516            None if migrate_variants.get_only_variant().is_some() => {
517                emit_default_dispatch(&MsgType::Migrate, contract_name)
518            }
519            None => quote! { #sylvia ::anyhow::bail!("migrate not implemented for contract") },
520        };
521
522        let reply_body = match override_entry_points.get_entry_point(MsgType::Reply) {
523            Some(entry_point) => entry_point.emit_multitest_dispatch(),
524            None => reply_variants
525                .get_only_variant()
526                .as_ref()
527                .map(|_reply| {
528                    let contract_ident = get_ident_from_type(contract_name);
529                    let contract_turbofish = if !generic_params.is_empty() {
530                        quote! { #contract_ident ::< #(#generic_params,)* > }
531                    } else {
532                        quote! { #contract_ident }
533                    };
534
535                    if sv_features.replies {
536                        quote! {
537                            let contract = #contract_turbofish ::new();
538                            dispatch_reply(deps, env, msg, contract).map_err(Into::into)
539                        }
540                    } else {
541                        let reply_name = _reply.name().to_case(Case::Snake);
542                        quote! {
543                            self. #reply_name ((deps, env).into(), msg).map_err(Into::into)
544                        }
545                    }
546                })
547                .unwrap_or_else(|| {
548                    quote! {
549                        #sylvia ::anyhow::bail!("reply not implemented for contract")
550                    }
551                }),
552        };
553
554        let custom_msg = custom.msg_or_default();
555        let custom_query = custom.query_or_default();
556
557        quote! {
558            impl #bracketed_generics #sylvia ::cw_multi_test::Contract<#custom_msg, #custom_query> for #contract_name #full_where_clause {
559                fn execute(
560                    &self,
561                    deps: #sylvia ::cw_std::DepsMut< #custom_query >,
562                    env: #sylvia ::cw_std::Env,
563                    info: #sylvia ::cw_std::MessageInfo,
564                    msg: Vec<u8>,
565                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Response<#custom_msg>> {
566                    #exec_body
567                }
568
569                fn instantiate(
570                    &self,
571                    deps: #sylvia ::cw_std::DepsMut<#custom_query>,
572                    env: #sylvia ::cw_std::Env,
573                    info: #sylvia ::cw_std::MessageInfo,
574                    msg: Vec<u8>,
575                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Response<#custom_msg>> {
576                    #instantiate_body
577                }
578
579                fn query(
580                    &self,
581                    deps: #sylvia ::cw_std::Deps<#custom_query>,
582                    env: #sylvia ::cw_std::Env,
583                    msg: Vec<u8>,
584                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Binary> {
585                    #query_body
586                }
587
588                fn sudo(
589                    &self,
590                    deps: #sylvia ::cw_std::DepsMut<#custom_query>,
591                    env: #sylvia ::cw_std::Env,
592                    msg: Vec<u8>,
593                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Response<#custom_msg>> {
594                    #sudo_body
595                }
596
597                fn reply(
598                    &self,
599                    deps: #sylvia ::cw_std::DepsMut<#custom_query>,
600                    env: #sylvia ::cw_std::Env,
601                    msg: #sylvia ::cw_std::Reply,
602                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Response<#custom_msg>> {
603                    #reply_body
604                }
605
606                fn migrate(
607                    &self,
608                    deps: #sylvia ::cw_std::DepsMut<#custom_query>,
609                    env: #sylvia ::cw_std::Env,
610                    msg: Vec<u8>,
611                ) -> #sylvia ::anyhow::Result<#sylvia ::cw_std::Response<#custom_msg>> {
612                    #migrate_body
613                }
614            }
615        }
616    }
617}
618
619fn emit_default_dispatch(msg_ty: &MsgType, contract_name: &Type) -> TokenStream {
620    let sylvia = crate_module();
621
622    let values = msg_ty.emit_ctx_values();
623    let msg_name = msg_ty.as_accessor_wrapper_name();
624    let api_msg = quote! { < #contract_name as #sylvia ::types::ContractApi> :: #msg_name };
625
626    quote! {
627        #sylvia ::cw_std::from_json::< #api_msg >(&msg)?
628            .dispatch(self, ( #values ))
629            .map_err(Into::into)
630    }
631}
632
633trait EmitMethods {
634    fn emit_mt_method_definition(
635        &self,
636        custom_msg: &Type,
637        mt_app: &Type,
638        error_type: &Type,
639        api: &TokenStream,
640    ) -> TokenStream;
641
642    fn emit_mt_method_declaration(
643        &self,
644        custom_msg: &Type,
645        error_type: &Type,
646        api: &TokenStream,
647    ) -> TokenStream;
648}
649
650impl EmitMethods for MsgVariant<'_> {
651    fn emit_mt_method_definition(
652        &self,
653        custom_msg: &Type,
654        mt_app: &Type,
655        error_type: &Type,
656        api: &TokenStream,
657    ) -> TokenStream {
658        let sylvia = crate_module();
659
660        let name = self.name();
661        let return_type = self.return_type();
662
663        let params: Vec<_> = self
664            .fields()
665            .iter()
666            .map(|field| field.emit_method_field_folded())
667            .collect();
668        let arguments = self.as_fields_names();
669        let type_name = self.msg_attr().msg_type().as_accessor_name();
670        let name = name.to_case(Case::Snake);
671
672        match self.msg_attr().msg_type() {
673            MsgType::Exec => quote! {
674                #[track_caller]
675                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::ExecProxy::< #error_type, #api :: #type_name, #mt_app, #custom_msg> {
676                    let msg = #api :: #type_name :: #name ( #(#arguments),* );
677
678                    #sylvia ::multitest::ExecProxy::new(&self.contract_addr, msg, &self.app)
679                }
680            },
681            MsgType::Query => {
682                quote! {
683                    fn #name (&self, #(#params,)* ) -> Result<#return_type, #error_type> {
684                        let msg = #api :: #type_name :: #name ( #(#arguments),* );
685
686                        (*self.app)
687                            .querier()
688                            .query_wasm_smart(self.contract_addr.clone(), &msg)
689                            .map_err(Into::into)
690                    }
691                }
692            }
693            MsgType::Sudo => quote! {
694                fn #name (&self, #(#params,)* ) -> Result< #sylvia ::cw_multi_test::AppResponse, #error_type> {
695                    let msg = #api :: #type_name :: #name ( #(#arguments),* );
696
697                    (*self.app)
698                        .app_mut()
699                        .wasm_sudo(self.contract_addr.clone(), &msg)
700                        .map_err(|err| err.downcast().unwrap())
701                }
702            },
703            MsgType::Migrate => quote! {
704                #[track_caller]
705                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::MigrateProxy::< #error_type, #api :: #type_name , #mt_app, #custom_msg> {
706                    let msg = #api :: #type_name ::new( #(#arguments),* );
707
708                    #sylvia ::multitest::MigrateProxy::new(&self.contract_addr, msg, &self.app)
709                }
710            },
711            _ => quote! {},
712        }
713    }
714
715    fn emit_mt_method_declaration(
716        &self,
717        custom_msg: &Type,
718        error_type: &Type,
719        api: &TokenStream,
720    ) -> TokenStream {
721        let sylvia = crate_module();
722
723        let name = self.name();
724        let return_type = self.return_type();
725
726        let params: Vec<_> = self
727            .fields()
728            .iter()
729            .map(|field| field.emit_method_field_folded())
730            .collect();
731        let type_name = self.msg_attr().msg_type().as_accessor_name();
732        let name = name.to_case(Case::Snake);
733
734        match self.msg_attr().msg_type() {
735            MsgType::Exec => quote! {
736                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::ExecProxy::< #error_type, #api:: #type_name, MtApp, #custom_msg>;
737            },
738            MsgType::Query => quote! {
739                fn #name (&self, #(#params,)* ) -> Result<#return_type, #error_type>;
740            },
741            MsgType::Sudo => quote! {
742                fn #name (&self, #(#params,)* ) -> Result< #sylvia ::cw_multi_test::AppResponse, #error_type>;
743            },
744            MsgType::Migrate => quote! {
745                #[track_caller]
746                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::MigrateProxy::< #error_type, #api :: #type_name, MtApp, #custom_msg>;
747            },
748            _ => quote! {},
749        }
750    }
751}