abstract_app/
endpoints.rs

1mod execute;
2mod ibc_callback;
3pub mod instantiate;
4mod migrate;
5mod module_ibc;
6mod query;
7mod reply;
8mod sudo;
9
10#[macro_export]
11/// Exports all entry-points, should be enabled by default.
12/// - instantiate
13/// - execute
14/// - query
15/// - migrate
16/// - reply
17/// - sudo
18///
19/// ## Usage
20/// Requires two arguments:
21/// 1. The App constant.
22/// 2. The App type.
23///
24/// ```ignore
25/// abstract_app::export_endpoints!(MY_APP, MyApp);
26/// ```
27macro_rules! export_endpoints {
28    ($app_const:expr, $app_type:ty) => {
29        $crate::__endpoints_without_custom__!($app_const, $app_type);
30
31        /// Execute entrypoint
32        #[::cosmwasm_std::entry_point]
33        pub fn execute(
34            deps: ::cosmwasm_std::DepsMut,
35            env: ::cosmwasm_std::Env,
36            info: ::cosmwasm_std::MessageInfo,
37            msg: <$app_type as $crate::sdk::base::ExecuteEndpoint>::ExecuteMsg,
38        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
39            use $crate::sdk::base::ExecuteEndpoint;
40            $app_const.execute(deps, env, info, msg)
41        }
42    };
43    ($app_const:expr, $app_type:ty, $custom_exec:ty) => {
44        $crate::__endpoints_without_custom__!($app_const, $app_type);
45
46        /// Execute entrypoint
47        #[::cosmwasm_std::entry_point]
48        pub fn execute(
49            deps: ::cosmwasm_std::DepsMut,
50            env: ::cosmwasm_std::Env,
51            info: ::cosmwasm_std::MessageInfo,
52            msg: $custom_exec,
53        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
54            use $crate::sdk::base::{CustomExecuteHandler, ExecuteEndpoint};
55            match CustomExecuteHandler::try_into_base(msg) {
56                Ok(default) => $app_const.execute(deps, env, info, default),
57                Err(custom) => custom.custom_execute(deps, env, info, $app_const),
58            }
59        }
60    };
61}
62
63#[macro_export]
64#[doc(hidden)]
65macro_rules! __endpoints_without_custom__ {
66    ($app_const:expr, $app_type:ty) => {
67        /// Instantiate entrypoint
68        #[::cosmwasm_std::entry_point]
69        pub fn instantiate(
70            deps: ::cosmwasm_std::DepsMut,
71            env: ::cosmwasm_std::Env,
72            info: ::cosmwasm_std::MessageInfo,
73            msg: <$app_type as $crate::sdk::base::InstantiateEndpoint>::InstantiateMsg,
74        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
75            use $crate::sdk::base::InstantiateEndpoint;
76            $app_const.instantiate(deps, env, info, msg)
77        }
78
79        /// Query entrypoint
80        #[::cosmwasm_std::entry_point]
81        pub fn query(
82            deps: ::cosmwasm_std::Deps,
83            env: ::cosmwasm_std::Env,
84            msg: <$app_type as $crate::sdk::base::QueryEndpoint>::QueryMsg,
85        ) -> Result<::cosmwasm_std::Binary, <$app_type as $crate::sdk::base::Handler>::Error> {
86            use $crate::sdk::base::QueryEndpoint;
87            $app_const.query(deps, env, msg)
88        }
89
90        /// Migrate entrypoint
91        #[::cosmwasm_std::entry_point]
92        pub fn migrate(
93            deps: ::cosmwasm_std::DepsMut,
94            env: ::cosmwasm_std::Env,
95            msg: <$app_type as $crate::sdk::base::MigrateEndpoint>::MigrateMsg,
96        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
97            use $crate::sdk::base::MigrateEndpoint;
98            $app_const.migrate(deps, env, msg)
99        }
100
101        // Reply entrypoint
102        #[::cosmwasm_std::entry_point]
103        pub fn reply(
104            deps: ::cosmwasm_std::DepsMut,
105            env: ::cosmwasm_std::Env,
106            msg: ::cosmwasm_std::Reply,
107        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
108            use $crate::sdk::base::ReplyEndpoint;
109            $app_const.reply(deps, env, msg)
110        }
111
112        // Sudo entrypoint
113        #[::cosmwasm_std::entry_point]
114        pub fn sudo(
115            deps: ::cosmwasm_std::DepsMut,
116            env: ::cosmwasm_std::Env,
117            msg: <$app_type as $crate::sdk::base::Handler>::SudoMsg,
118        ) -> Result<::cosmwasm_std::Response, <$app_type as $crate::sdk::base::Handler>::Error> {
119            use $crate::sdk::base::SudoEndpoint;
120            $app_const.sudo(deps, env, msg)
121        }
122    };
123}
124
125#[cfg(test)]
126mod test {
127    #![allow(clippy::needless_borrows_for_generic_args)]
128    use crate::mock::*;
129    use crate::sdk::base::{
130        ExecuteEndpoint, InstantiateEndpoint, MigrateEndpoint, QueryEndpoint, ReplyEndpoint,
131        SudoEndpoint,
132    };
133    use abstract_sdk::base::CustomExecuteHandler;
134    use abstract_testing::prelude::*;
135    use cosmwasm_std::{Binary, SubMsgResult};
136
137    #[coverage_helper::test]
138    fn exports_endpoints() {
139        export_endpoints!(MOCK_APP_WITH_DEP, MockAppContract);
140
141        let mut deps = mock_dependencies();
142        let env = mock_env_validated(deps.api);
143        let abstr = AbstractMockAddrs::new(deps.api);
144
145        // init
146        let init_msg = app::InstantiateMsg {
147            base: app::BaseInstantiateMsg {
148                account: abstr.account,
149            },
150            module: MockInitMsg {},
151        };
152        let actual_init = instantiate(
153            deps.as_mut(),
154            env.clone(),
155            message_info(&abstr.owner, &[]),
156            init_msg.clone(),
157        );
158        let expected_init = MOCK_APP_WITH_DEP.instantiate(
159            deps.as_mut(),
160            env.clone(),
161            message_info(&abstr.owner, &[]),
162            init_msg,
163        );
164        assert_eq!(actual_init, expected_init);
165
166        // exec
167        let exec_msg = app::ExecuteMsg::Module(MockExecMsg::DoSomething {});
168        let actual_exec = execute(
169            deps.as_mut(),
170            env.clone(),
171            message_info(&abstr.owner, &[]),
172            exec_msg.clone(),
173        );
174        let expected_exec = MOCK_APP_WITH_DEP.execute(
175            deps.as_mut(),
176            env.clone(),
177            message_info(&abstr.owner, &[]),
178            exec_msg,
179        );
180        assert_eq!(actual_exec, expected_exec);
181
182        // query
183        let query_msg = app::QueryMsg::Module(MockQueryMsg::GetSomething {});
184        let actual_query = query(deps.as_ref(), env.clone(), query_msg.clone());
185        let expected_query = MOCK_APP_WITH_DEP.query(deps.as_ref(), env.clone(), query_msg);
186        assert_eq!(actual_query, expected_query);
187
188        // migrate
189        let migrate_msg = app::MigrateMsg {
190            base: app::BaseMigrateMsg {},
191            module: MockMigrateMsg,
192        };
193        let actual_migrate = migrate(deps.as_mut(), env.clone(), migrate_msg.clone());
194        let expected_migrate = MOCK_APP_WITH_DEP.migrate(deps.as_mut(), env.clone(), migrate_msg);
195        assert_eq!(actual_migrate, expected_migrate);
196
197        // sudo
198        let sudo_msg = MockSudoMsg {};
199        let actual_sudo = sudo(deps.as_mut(), env.clone(), sudo_msg.clone());
200        let expected_sudo = MOCK_APP_WITH_DEP.sudo(deps.as_mut(), env.clone(), sudo_msg);
201        assert_eq!(actual_sudo, expected_sudo);
202
203        // reply
204        let reply_msg = ::cosmwasm_std::Reply {
205            id: 0,
206            result: SubMsgResult::Err("test".into()),
207            payload: Binary::default(),
208            gas_used: 0,
209        };
210        let actual_reply = reply(deps.as_mut(), env.clone(), reply_msg.clone());
211        let expected_reply = MOCK_APP_WITH_DEP.reply(deps.as_mut(), env, reply_msg);
212        assert_eq!(actual_reply, expected_reply);
213    }
214
215    #[coverage_helper::test]
216    fn exports_endpoints_custom() {
217        #[cosmwasm_schema::cw_serde]
218        #[derive(cw_orch::ExecuteFns)]
219        pub enum CustomExecMsg {
220            Base(abstract_std::app::BaseExecuteMsg),
221            Module(crate::mock::MockExecMsg),
222            IbcCallback(abstract_std::ibc::IbcResponseMsg),
223            ModuleIbc(abstract_std::ibc::ModuleIbcMsg),
224            Foo {},
225        }
226
227        impl From<crate::mock::MockExecMsg> for CustomExecMsg {
228            fn from(request: crate::mock::MockExecMsg) -> Self {
229                Self::Module(request)
230            }
231        }
232
233        impl CustomExecuteHandler<MockAppContract> for CustomExecMsg {
234            type ExecuteMsg = crate::mock::ExecuteMsg;
235
236            fn try_into_base(self) -> Result<Self::ExecuteMsg, Self> {
237                match self {
238                    CustomExecMsg::Base(msg) => Ok(Self::ExecuteMsg::Base(msg)),
239                    CustomExecMsg::Module(msg) => Ok(Self::ExecuteMsg::Module(msg)),
240                    CustomExecMsg::IbcCallback(msg) => Ok(Self::ExecuteMsg::IbcCallback(msg)),
241                    CustomExecMsg::ModuleIbc(msg) => Ok(Self::ExecuteMsg::ModuleIbc(msg)),
242                    _ => Err(self),
243                }
244            }
245
246            fn custom_execute(
247                self,
248                _deps: cosmwasm_std::DepsMut,
249                _env: cosmwasm_std::Env,
250                _info: cosmwasm_std::MessageInfo,
251                _module: MockAppContract,
252            ) -> Result<cosmwasm_std::Response, crate::mock::MockError> {
253                Ok(cosmwasm_std::Response::new().set_data(b"foo"))
254            }
255        }
256
257        export_endpoints!(MOCK_APP_WITH_DEP, MockAppContract, CustomExecMsg);
258
259        let mut deps = mock_dependencies();
260        let env = mock_env_validated(deps.api);
261        let abstr = AbstractMockAddrs::new(deps.api);
262
263        // custom
264        let actual_custom_exec = execute(
265            deps.as_mut(),
266            env.clone(),
267            message_info(&abstr.owner, &[]),
268            CustomExecMsg::Foo {},
269        )
270        .unwrap();
271        let expected_custom_exec =
272            cosmwasm_std::Response::<cosmwasm_std::Empty>::new().set_data(b"foo");
273        assert_eq!(actual_custom_exec, expected_custom_exec);
274
275        // Ensure nothing broken
276
277        // init
278        let init_msg = app::InstantiateMsg {
279            base: app::BaseInstantiateMsg {
280                account: test_account(deps.api),
281            },
282            module: MockInitMsg {},
283        };
284        let actual_init = instantiate(
285            deps.as_mut(),
286            env.clone(),
287            message_info(&abstr.owner, &[]),
288            init_msg.clone(),
289        );
290        let expected_init = MOCK_APP_WITH_DEP.instantiate(
291            deps.as_mut(),
292            env.clone(),
293            message_info(&abstr.owner, &[]),
294            init_msg,
295        );
296        assert_eq!(actual_init, expected_init);
297
298        // exec
299        let exec_msg = app::ExecuteMsg::Module(MockExecMsg::DoSomething {});
300        let actual_exec = execute(
301            deps.as_mut(),
302            env.clone(),
303            message_info(&abstr.owner, &[]),
304            CustomExecMsg::Module(MockExecMsg::DoSomething {}),
305        );
306        let expected_exec = MOCK_APP_WITH_DEP.execute(
307            deps.as_mut(),
308            env.clone(),
309            message_info(&abstr.owner, &[]),
310            exec_msg,
311        );
312        assert_eq!(actual_exec, expected_exec);
313
314        // query
315        let query_msg = app::QueryMsg::Module(MockQueryMsg::GetSomething {});
316        let actual_query = query(deps.as_ref(), env.clone(), query_msg.clone());
317        let expected_query = MOCK_APP_WITH_DEP.query(deps.as_ref(), env.clone(), query_msg);
318        assert_eq!(actual_query, expected_query);
319
320        // migrate
321        let migrate_msg = app::MigrateMsg {
322            base: app::BaseMigrateMsg {},
323            module: MockMigrateMsg,
324        };
325        let actual_migrate = migrate(deps.as_mut(), env.clone(), migrate_msg.clone());
326        let expected_migrate = MOCK_APP_WITH_DEP.migrate(deps.as_mut(), env.clone(), migrate_msg);
327        assert_eq!(actual_migrate, expected_migrate);
328
329        // sudo
330        let sudo_msg = MockSudoMsg {};
331        let actual_sudo = sudo(deps.as_mut(), env.clone(), sudo_msg.clone());
332        let expected_sudo = MOCK_APP_WITH_DEP.sudo(deps.as_mut(), env.clone(), sudo_msg);
333        assert_eq!(actual_sudo, expected_sudo);
334
335        // reply
336        let reply_msg = ::cosmwasm_std::Reply {
337            id: 0,
338            result: SubMsgResult::Err("test".into()),
339            payload: Binary::default(),
340            gas_used: 0,
341        };
342        let actual_reply = reply(deps.as_mut(), env.clone(), reply_msg.clone());
343        let expected_reply = MOCK_APP_WITH_DEP.reply(deps.as_mut(), env, reply_msg);
344        assert_eq!(actual_reply, expected_reply);
345    }
346}