1#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
2
3mod endpoints;
4pub mod error;
5pub mod features;
6pub(crate) mod handler;
7pub mod msgs;
8#[cfg(feature = "schema")]
9pub mod schema;
10pub mod state;
11pub(crate) use abstract_sdk::base::*;
12pub use error::AppError;
13
14pub use crate::state::AppContract;
15pub type AppResult<C = cosmwasm_std::Empty> = Result<cosmwasm_std::Response<C>, AppError>;
16
17pub use abstract_std as std;
19pub use abstract_sdk as sdk;
21
22pub use crate::std::objects;
23pub mod traits {
24 pub use abstract_sdk::{features::*, prelude::*};
25}
26
27mod interface;
28pub use abstract_interface;
29#[cfg(feature = "test-utils")]
30pub use abstract_testing;
31
32#[cfg(feature = "test-utils")]
33pub mod mock {
34 use abstract_interface::{AppDeployer, DependencyCreation, RegisteredModule};
35 pub use abstract_std::app;
36 use abstract_std::{
37 account::ModuleInstallConfig,
38 objects::{dependency::StaticDependency, module::ModuleInfo},
39 IBC_CLIENT,
40 };
41 use cosmwasm_schema::QueryResponses;
42 pub(crate) use cosmwasm_std::testing::{message_info, mock_dependencies};
43 use cosmwasm_std::{to_json_binary, Response, StdError};
44 use cw_controllers::AdminError;
45 use cw_orch::prelude::*;
46 use cw_storage_plus::Item;
47
48 pub type AppTestResult = Result<(), MockError>;
49
50 crate::app_msg_types!(MockAppContract, MockExecMsg, MockQueryMsg);
51
52 #[cosmwasm_schema::cw_serde]
53 pub struct MockInitMsg {}
54
55 #[cosmwasm_schema::cw_serde]
56 #[derive(cw_orch::ExecuteFns)]
57 pub enum MockExecMsg {
58 DoSomething {},
59 DoSomethingAdmin {},
60 }
61
62 #[cosmwasm_schema::cw_serde]
63 #[derive(cw_orch::QueryFns, QueryResponses)]
64 pub enum MockQueryMsg {
65 #[returns(MockQueryResponse)]
66 GetSomething {},
67
68 #[returns(ReceivedIbcCallbackStatus)]
69 GetReceivedIbcCallbackStatus {},
70 }
71
72 #[cosmwasm_schema::cw_serde]
73 pub struct MockQueryResponse {}
74
75 #[cosmwasm_schema::cw_serde]
76 pub struct ReceivedIbcCallbackStatus {
77 pub received: bool,
78 }
79
80 #[cosmwasm_schema::cw_serde]
81 pub struct MockMigrateMsg;
82
83 #[cosmwasm_schema::cw_serde]
84 pub struct MockSudoMsg;
85
86 use abstract_sdk::{base::InstantiateEndpoint, features::Dependencies, AbstractSdkError};
87 use abstract_testing::{mock_env_validated, prelude::*};
88 use thiserror::Error;
89
90 use self::interface::MockAppWithDepI;
91 use crate::{AppContract, AppError};
92
93 #[derive(Error, Debug, PartialEq)]
94 pub enum MockError {
95 #[error(transparent)]
96 Std(#[from] StdError),
97
98 #[error(transparent)]
99 DappError(#[from] AppError),
100
101 #[error(transparent)]
102 Abstract(#[from] abstract_std::AbstractError),
103
104 #[error(transparent)]
105 AbstractSdk(#[from] AbstractSdkError),
106
107 #[error(transparent)]
108 Admin(#[from] AdminError),
109 }
110
111 pub type MockAppContract = AppContract<
112 MockError,
114 MockInitMsg,
115 MockExecMsg,
116 MockQueryMsg,
117 MockMigrateMsg,
118 MockSudoMsg,
119 >;
120
121 pub const BASIC_MOCK_APP: MockAppContract =
122 MockAppContract::new(TEST_MODULE_ID, TEST_VERSION, None);
123
124 pub const IBC_CALLBACK_RECEIVED: Item<bool> = Item::new("ibc_callback_received");
126
127 pub const MOCK_APP_WITH_DEP: MockAppContract =
128 MockAppContract::new(TEST_WITH_DEP_MODULE_ID, TEST_VERSION, None)
129 .with_instantiate(|deps, _, _, _, _| {
130 IBC_CALLBACK_RECEIVED.save(deps.storage, &false)?;
131 Ok(Response::new().set_data("mock_init".as_bytes()))
132 })
133 .with_execute(|_, _, _, _, _| Ok(Response::new().set_data("mock_exec".as_bytes())))
134 .with_query(|deps, _, _, msg| match msg {
135 MockQueryMsg::GetSomething {} => {
136 to_json_binary(&MockQueryResponse {}).map_err(Into::into)
137 }
138 MockQueryMsg::GetReceivedIbcCallbackStatus {} => {
139 to_json_binary(&ReceivedIbcCallbackStatus {
140 received: IBC_CALLBACK_RECEIVED.load(deps.storage)?,
141 })
142 .map_err(Into::into)
143 }
144 })
145 .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes())))
146 .with_ibc_callback(|deps, _, _, _, _| {
147 IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap();
148
149 Ok(Response::new().add_attribute("mock_callback", "executed"))
150 })
151 .with_dependencies(&[
152 StaticDependency::new(TEST_MODULE_ID, &[TEST_VERSION]),
153 StaticDependency::new(IBC_CLIENT, &[abstract_std::constants::ABSTRACT_VERSION]),
154 ])
155 .with_replies(&[(1u64, |_, _, _, msg| {
156 #[allow(deprecated)]
157 Ok(Response::new().set_data(msg.result.unwrap().data.unwrap()))
158 })])
159 .with_migrate(|_, _, _, _| Ok(Response::new().set_data("mock_migrate".as_bytes())));
160
161 crate::cw_orch_interface!(MOCK_APP_WITH_DEP, MockAppContract, MockAppWithDepI);
162
163 pub mod mock_app_dependency {
165 use abstract_testing::prelude::{TEST_MODULE_ID, TEST_VERSION};
166 use cosmwasm_std::{to_json_binary, Response};
167
168 use super::{MockAppContract, MockQueryResponse};
169
170 pub const MOCK_APP: MockAppContract =
171 MockAppContract::new(TEST_MODULE_ID, TEST_VERSION, None)
172 .with_instantiate(|_, _, _, _, _| {
173 Ok(Response::new().set_data("mock_init".as_bytes()))
174 })
175 .with_execute(|_, _, _, _, _| Ok(Response::new().set_data("mock_exec".as_bytes())))
176 .with_query(|_, _, _, _| to_json_binary(&MockQueryResponse {}).map_err(Into::into));
177
178 crate::cw_orch_interface!(MOCK_APP, MockAppContract, MockAppI);
179 }
180
181 impl<Chain: CwEnv> DependencyCreation for MockAppWithDepI<Chain> {
182 type DependenciesConfig = Empty;
183 fn dependency_install_configs(
184 _configuration: Self::DependenciesConfig,
185 ) -> Result<Vec<ModuleInstallConfig>, abstract_interface::AbstractInterfaceError> {
186 let test_module = ModuleInstallConfig::new(
187 ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?,
188 Some(to_json_binary(&MockInitMsg {})?),
189 );
190 let ibc_client = ModuleInstallConfig::new(
191 ModuleInfo::from_id(IBC_CLIENT, abstract_std::constants::ABSTRACT_VERSION.into())?,
192 None,
193 );
194 Ok(vec![test_module, ibc_client])
195 }
196 }
197
198 crate::export_endpoints!(MOCK_APP_WITH_DEP, MockAppContract);
199
200 pub fn app_base_mock_querier(mock_api: cosmwasm_std::testing::MockApi) -> MockQuerierBuilder {
201 let abstr = AbstractMockAddrs::new(mock_api);
202 MockQuerierBuilder::default()
203 .with_smart_handler(&abstr.module_factory, |_msg| panic!("unexpected message"))
204 }
205
206 pub fn mock_init() -> MockDeps {
209 let mut deps = mock_dependencies();
210 let abstr = AbstractMockAddrs::new(deps.api);
211 let info = message_info(&abstr.module_factory, &[]);
212 let env = mock_env_validated(deps.api);
213 let account = test_account(deps.api);
214
215 deps.querier = app_base_mock_querier(deps.api).build();
216
217 let msg = app::InstantiateMsg {
218 base: app::BaseInstantiateMsg { account },
219 module: MockInitMsg {},
220 };
221
222 BASIC_MOCK_APP
223 .instantiate(deps.as_mut(), env, info, msg)
224 .unwrap();
225
226 deps
227 }
228
229 type Exec = app::ExecuteMsg<MockExecMsg>;
230 type Query = app::QueryMsg<MockQueryMsg>;
231 type Init = app::InstantiateMsg<MockInitMsg>;
232 type Migrate = app::MigrateMsg<MockMigrateMsg>;
233
234 #[cw_orch::interface(Init, Exec, Query, Migrate)]
235 pub struct MockAppI<Chain>;
236
237 impl<Chain> RegisteredModule for MockAppI<Chain> {
238 type InitMsg = MockInitMsg;
239
240 fn module_id<'a>() -> &'a str {
241 BASIC_MOCK_APP.module_id()
242 }
243
244 fn module_version<'a>() -> &'a str {
245 BASIC_MOCK_APP.version()
246 }
247
248 fn dependencies<'a>() -> &'a [StaticDependency] {
249 BASIC_MOCK_APP.dependencies()
250 }
251 }
252
253 impl<T: cw_orch::prelude::CwEnv> AppDeployer<T> for MockAppI<T> {}
254
255 impl<T: cw_orch::prelude::CwEnv> Uploadable for MockAppI<T> {
256 fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
257 Box::new(
258 ContractWrapper::new_with_empty(self::execute, self::instantiate, self::query)
259 .with_migrate(self::migrate),
260 )
261 }
262 }
263
264 #[macro_export]
265 macro_rules! gen_app_mock {
266 ($name:ident,$id:expr, $version:expr, $deps:expr) => {
267 use $crate::std::app;
268 use ::abstract_app::mock::{MockExecMsg, MockInitMsg, MockMigrateMsg, MockQueryMsg};
269 use ::cw_orch::prelude::*;
270 use $crate::sdk::base::Handler;
271 use $crate::sdk::features::AccountIdentification;
272 use $crate::sdk::{Execution, TransferInterface};
273
274
275 type Exec = app::ExecuteMsg<MockExecMsg>;
276 type Query = app::QueryMsg<MockQueryMsg>;
277 type Init = app::InstantiateMsg<MockInitMsg>;
278 type Migrate = app::MigrateMsg<MockMigrateMsg>;
279 const MOCK_APP_WITH_DEP: ::abstract_app::mock::MockAppContract = ::abstract_app::mock::MockAppContract::new($id, $version, None)
280 .with_dependencies($deps)
281 .with_execute(|deps, env, info, module, msg| {
282 match msg {
283 MockExecMsg::DoSomethingAdmin{} => {
284 module.admin.assert_admin(deps.as_ref(), &env, &info.sender)?;
285 },
286 _ => {},
287 }
288 Ok(::cosmwasm_std::Response::new().set_data("mock_exec".as_bytes()))
289 })
290 .with_instantiate(|deps, env, info, module, msg| {
291 let mut response = ::cosmwasm_std::Response::new().set_data("mock_init".as_bytes());
292 if module.info().0 == "tester:mock-app1" {
294 println!("checking address of adapter1");
295 let account = module.admin.get(deps.as_ref())?.unwrap();
296 let adapter1_addr = $crate::std::account::state::ACCOUNT_MODULES.query(&deps.querier,account, "tester:mock-adapter1")?;
298 ::cosmwasm_std::ensure!(
300 adapter1_addr.is_some(),
301 ::cosmwasm_std::StdError::generic_err("no address")
302 );
303 println!("adapter_addr: {adapter1_addr:?}");
304 let account_addr = module.account(deps.as_ref())?;
306 let balance = deps.querier.query_balance(account_addr.addr(), "TEST")?;
307 if !balance.amount.is_zero() {
308 println!("sending amount from account: {balance:?}");
309 let action = module
310 .bank(deps.as_ref())
311 .transfer::<::cosmwasm_std::Coin>(
312 vec![balance.into()],
313 &adapter1_addr.unwrap(),
314 )?;
315 let msg = module.executor(deps.as_ref()).execute(vec![action])?;
316 println!("message: {msg:?}");
317 response = response.add_message(msg);
318 }
319 Ok(response)}
320 else {
321 Ok(response)}
322 });
323
324 fn mock_instantiate(
325 deps: ::cosmwasm_std::DepsMut,
326 env: ::cosmwasm_std::Env,
327 info: ::cosmwasm_std::MessageInfo,
328 msg: <::abstract_app::mock::MockAppContract as $crate::sdk::base::InstantiateEndpoint>::InstantiateMsg,
329 ) -> Result<::cosmwasm_std::Response, <::abstract_app::mock::MockAppContract as $crate::sdk::base::Handler>::Error> {
330 use $crate::sdk::base::InstantiateEndpoint;
331 MOCK_APP_WITH_DEP.instantiate(deps, env, info, msg)
332 }
333
334 fn mock_execute(
336 deps: ::cosmwasm_std::DepsMut,
337 env: ::cosmwasm_std::Env,
338 info: ::cosmwasm_std::MessageInfo,
339 msg: <::abstract_app::mock::MockAppContract as $crate::sdk::base::ExecuteEndpoint>::ExecuteMsg,
340 ) -> Result<::cosmwasm_std::Response, <::abstract_app::mock::MockAppContract as $crate::sdk::base::Handler>::Error> {
341 use $crate::sdk::base::ExecuteEndpoint;
342 MOCK_APP_WITH_DEP.execute(deps, env, info, msg)
343 }
344
345 fn mock_query(
347 deps: ::cosmwasm_std::Deps,
348 env: ::cosmwasm_std::Env,
349 msg: <::abstract_app::mock::MockAppContract as $crate::sdk::base::QueryEndpoint>::QueryMsg,
350 ) -> Result<::cosmwasm_std::Binary, <::abstract_app::mock::MockAppContract as $crate::sdk::base::Handler>::Error> {
351 use $crate::sdk::base::QueryEndpoint;
352 MOCK_APP_WITH_DEP.query(deps, env, msg)
353 }
354
355 fn mock_migrate(
356 deps: ::cosmwasm_std::DepsMut,
357 env: ::cosmwasm_std::Env,
358 msg: <::abstract_app::mock::MockAppContract as $crate::sdk::base::MigrateEndpoint>::MigrateMsg,
359 ) -> Result<::cosmwasm_std::Response, <::abstract_app::mock::MockAppContract as $crate::sdk::base::Handler>::Error> {
360 use $crate::sdk::base::MigrateEndpoint;
361 MOCK_APP_WITH_DEP.migrate(deps, env, msg)
362 }
363
364 #[cw_orch::interface(Init, Exec, Query, Migrate)]
365 pub struct $name;
366
367 impl<T: cw_orch::prelude::CwEnv> ::abstract_interface::AppDeployer<T> for $name <T> {}
368
369 impl<Chain> $crate::abstract_interface::RegisteredModule for $name<Chain> {
370 type InitMsg = MockInitMsg;
371
372 fn module_id<'a>() -> &'a str {
373 MOCK_APP_WITH_DEP.module_id()
374 }
375
376 fn module_version<'a>() -> &'a str {
377 MOCK_APP_WITH_DEP.version()
378 }
379
380 fn dependencies<'a>() -> &'a [$crate::objects::dependency::StaticDependency] {
381 MOCK_APP_WITH_DEP.dependencies()
382 }
383 }
384
385 impl<T: cw_orch::prelude::CwEnv> Uploadable for $name<T> {
386 fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
387 Box::new(ContractWrapper::<
388 Exec,
389 _,
390 _,
391 _,
392 _,
393 _,
394 >::new_with_empty(
395 self::mock_execute,
396 self::mock_instantiate,
397 self::mock_query,
398 ).with_migrate(self::mock_migrate))
399 }
400 }
401
402 impl<Chain: ::cw_orch::environment::CwEnv> $name <Chain> {
403 pub fn new_test(chain: Chain) -> Self {
404 Self(
405 cw_orch::contract::Contract::new($id,chain),
406 )
407 }
408 }
409 };
410}
411}