andromeda_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{parse::Parser, parse_macro_input, DeriveInput};
4
5/// Taken from: https://github.com/DA0-DA0/dao-contracts/blob/74bd3881fdd86829e5e8b132b9952dd64f2d0737/packages/dao-macros/src/lib.rs#L9
6/// Used to merge two enums together.
7fn merge_variants(left: TokenStream, right: TokenStream) -> TokenStream {
8    use syn::Data::Enum;
9    use syn::DataEnum;
10
11    let mut left: DeriveInput = parse_macro_input!(left);
12    let right: DeriveInput = parse_macro_input!(right);
13
14    if let (
15        Enum(DataEnum { variants, .. }),
16        Enum(DataEnum {
17            variants: to_add, ..
18        }),
19    ) = (&mut left.data, right.data)
20    {
21        variants.extend(to_add);
22
23        quote! { #left }.into()
24    } else {
25        syn::Error::new(left.ident.span(), "variants may only be added for enums")
26            .to_compile_error()
27            .into()
28    }
29}
30
31#[proc_macro_attribute]
32/// Attaches all relevant ADO messages to a set of Execute messages for a given contract.
33///
34/// Also derives the `AsRefStr` trait for the enum allowing the use of `as_ref_str` to get the string representation of the enum variant.
35///
36/// e.g. `ExecuteMsg::MyMessage{..}.as_ref_str()` will return `"MyMessage"`
37///
38/// **Must be placed before `#[cw_serde]`**
39pub fn andr_exec(_args: TokenStream, input: TokenStream) -> TokenStream {
40    #[allow(unused_mut)]
41    let mut merged = merge_variants(
42        input,
43        quote! {
44            enum Right {
45                #[serde(rename="amp_receive")]
46                AMPReceive(::andromeda_std::amp::messages::AMPPkt),
47                Ownership(::andromeda_std::ado_base::ownership::OwnershipMessage),
48                UpdateKernelAddress {
49                    address: ::cosmwasm_std::Addr,
50                },
51                UpdateAppContract {
52                    address: String,
53                },
54                Permissioning(::andromeda_std::ado_base::permissioning::PermissioningMessage),
55            }
56        }
57        .into(),
58    );
59    #[cfg(feature = "modules")]
60    {
61        merged = merge_variants(
62            merged,
63            quote! {
64                enum Right {
65                    RegisterModule {
66                        module: ::andromeda_std::ado_base::Module,
67                    },
68                    DeregisterModule {
69                        module_idx: ::cosmwasm_std::Uint64,
70                    },
71                    AlterModule {
72                        module_idx: ::cosmwasm_std::Uint64,
73                        module: ::andromeda_std::ado_base::Module,
74                    },
75                }
76            }
77            .into(),
78        )
79    }
80    let input = parse_macro_input!(merged);
81    TokenStream::from(andr_exec_derive(input).into_token_stream())
82}
83
84/// Derives the `AsRefStr` trait for a given enum allowing the use of `as_ref_str` to get the string representation of the enum.
85fn andr_exec_derive(input: DeriveInput) -> DeriveInput {
86    use syn::parse_quote;
87
88    match input.data {
89        syn::Data::Enum(_) => parse_quote! {
90            #[derive(::andromeda_std::AsRefStr)]
91            #input
92        },
93        _ => panic!("unions are not supported"),
94    }
95}
96
97/// Adjusted from https://users.rust-lang.org/t/solved-derive-and-proc-macro-add-field-to-an-existing-struct/52307/3
98/// Adds all fields required to instantiate an ADO to a struct.
99///
100/// Includes:
101/// 1. Kernel Address for interacting with aOS
102/// 2. Owner of the ADO (optional, assumed to be sender otherwise)
103/// 3. Modules (optional, requires `modules` feature)
104#[proc_macro_attribute]
105pub fn andr_instantiate(_args: TokenStream, input: TokenStream) -> TokenStream {
106    let mut ast = parse_macro_input!(input as DeriveInput);
107    match &mut ast.data {
108        syn::Data::Struct(ref mut struct_data) => {
109            if let syn::Fields::Named(fields) = &mut struct_data.fields {
110                fields.named.push(
111                    syn::Field::parse_named
112                        .parse2(quote! { pub kernel_address: String })
113                        .unwrap(),
114                );
115                fields.named.push(
116                    syn::Field::parse_named
117                        .parse2(quote! { pub owner: Option<String> })
118                        .unwrap(),
119                );
120            }
121
122            quote! {
123                #ast
124            }
125            .into()
126        }
127        _ => panic!("Macro only works with structs"),
128    }
129}
130
131#[proc_macro_attribute]
132pub fn andr_instantiate_modules(_args: TokenStream, input: TokenStream) -> TokenStream {
133    let mut ast = parse_macro_input!(input as DeriveInput);
134    match &mut ast.data {
135        syn::Data::Struct(ref mut struct_data) => {
136            if let syn::Fields::Named(fields) = &mut struct_data.fields {
137                fields.named.push(
138                    syn::Field::parse_named
139                        .parse2(
140                            quote! { pub modules: Option<Vec<::andromeda_std::ado_base::Module>> },
141                        )
142                        .unwrap(),
143                );
144            }
145            quote! {
146                #ast
147            }
148            .into()
149        }
150        _ => panic!("Macro only works with structs"),
151    }
152}
153
154#[proc_macro_attribute]
155/// Attaches all relevant ADO messages to a set of Query messages for a given contract.
156///
157/// **Must be placed before `#[cw_serde]`**
158pub fn andr_query(_metadata: TokenStream, input: TokenStream) -> TokenStream {
159    #[allow(unused_mut)]
160    let mut merged = merge_variants(
161        input,
162        quote! {
163            enum Right {
164                #[returns(andromeda_std::ado_base::ownership::ContractOwnerResponse)]
165                Owner {},
166                #[returns(andromeda_std::ado_base::ownership::ContractPotentialOwnerResponse)]
167                OwnershipRequest {},
168                #[returns(andromeda_std::ado_base::ado_type::TypeResponse)]
169                Type {},
170                #[returns(andromeda_std::ado_base::kernel_address::KernelAddressResponse)]
171                KernelAddress {},
172                #[returns(andromeda_std::ado_base::app_contract::AppContractResponse)]
173                AppContract {},
174                #[returns(andromeda_std::ado_base::ownership::PublisherResponse)]
175                OriginalPublisher {},
176                #[returns(andromeda_std::ado_base::block_height::BlockHeightResponse)]
177                BlockHeightUponCreation {},
178                #[returns(andromeda_std::ado_base::version::VersionResponse)]
179                Version {},
180                #[returns(Vec<::andromeda_std::ado_base::permissioning::PermissionInfo>)]
181                Permissions { actor: String, limit: Option<u32>, start_after: Option<String> },
182                #[returns(Vec<String>)]
183                PermissionedActions { },
184            }
185        }
186        .into(),
187    );
188
189    #[cfg(feature = "modules")]
190    {
191        merged = merge_variants(
192            merged,
193            quote! {
194                enum Right {
195                    #[returns(andromeda_std::ado_base::Module)]
196                    Module { id: ::cosmwasm_std::Uint64 },
197                    #[returns(Vec<String>)]
198                    ModuleIds {},
199                }
200            }
201            .into(),
202        );
203    }
204    #[cfg(feature = "module_hooks")]
205    {
206        merged = merge_variants(
207            merged,
208            quote! {
209                enum Right {
210                    #[returns(::cosmwasm_std::Binary)]
211                    AndrHook(::andromeda_std::ado_base::hooks::AndromedaHook),
212                }
213            }
214            .into(),
215        );
216    }
217
218    merged
219}