abstract_app/endpoints/
query.rs

1use abstract_sdk::feature_objects::{AnsHost, RegistryContract};
2use abstract_std::{
3    app::{AppConfigResponse, AppQueryMsg, BaseQueryMsg, QueryMsg},
4    native_addrs,
5    objects::{
6        gov_type::TopLevelOwnerResponse,
7        module_version::{ModuleDataResponse, MODULE},
8        ownership::nested_admin::query_top_level_owner_addr,
9    },
10};
11use cosmwasm_std::{to_json_binary, Binary, Deps, Env, StdError, StdResult};
12use cw_controllers::AdminResponse;
13
14use crate::{
15    state::{AppContract, ContractError},
16    Handler, QueryEndpoint,
17};
18
19impl<
20        Error: ContractError,
21        CustomInitMsg,
22        CustomExecMsg,
23        CustomQueryMsg: AppQueryMsg,
24        CustomMigrateMsg,
25        SudoMsg,
26    > QueryEndpoint
27    for AppContract<Error, CustomInitMsg, CustomExecMsg, CustomQueryMsg, CustomMigrateMsg, SudoMsg>
28{
29    type QueryMsg = QueryMsg<CustomQueryMsg>;
30
31    fn query(&self, deps: Deps, env: Env, msg: Self::QueryMsg) -> Result<Binary, Error> {
32        match msg {
33            QueryMsg::Base(msg) => self.base_query(deps, msg).map_err(Into::into),
34            QueryMsg::Module(msg) => self.query_handler()?(deps, env, self, msg),
35        }
36    }
37}
38/// Where we dispatch the queries for the AppContract
39/// These BaseQueryMsg declarations can be found in `abstract_sdk::std::common_module::app_msg`
40impl<
41        Error: ContractError,
42        CustomInitMsg,
43        CustomExecMsg,
44        CustomQueryMsg,
45        CustomMigrateMsg,
46        SudoMsg,
47    > AppContract<Error, CustomInitMsg, CustomExecMsg, CustomQueryMsg, CustomMigrateMsg, SudoMsg>
48{
49    pub fn base_query(&self, deps: Deps, query: BaseQueryMsg) -> StdResult<Binary> {
50        match query {
51            BaseQueryMsg::BaseConfig {} => to_json_binary(&self.dapp_config(deps)?),
52            BaseQueryMsg::BaseAdmin {} => to_json_binary(&self.admin(deps)?),
53            BaseQueryMsg::ModuleData {} => to_json_binary(&self.module_data(deps)?),
54            BaseQueryMsg::TopLevelOwner {} => to_json_binary(&self.top_level_owner(deps)?),
55        }
56    }
57
58    fn dapp_config(&self, deps: Deps) -> StdResult<AppConfigResponse> {
59        let state = self.base_state.load(deps.storage)?;
60        let abstract_code_id = native_addrs::abstract_code_id(&deps.querier, state.account.addr())?;
61        Ok(AppConfigResponse {
62            account: state.account.into_addr(),
63            ans_host_address: AnsHost::new(deps, abstract_code_id)
64                .map_err(|e| StdError::generic_err(e.to_string()))?
65                .address,
66            registry_address: RegistryContract::new(deps, abstract_code_id)
67                .map_err(|e| StdError::generic_err(e.to_string()))?
68                .address,
69        })
70    }
71
72    fn admin(&self, deps: Deps) -> StdResult<AdminResponse> {
73        self.admin.query_admin(deps)
74    }
75
76    fn module_data(&self, deps: Deps) -> StdResult<ModuleDataResponse> {
77        let module_data = MODULE.load(deps.storage)?;
78        Ok(ModuleDataResponse {
79            module_id: module_data.module,
80            version: module_data.version,
81            dependencies: module_data
82                .dependencies
83                .into_iter()
84                .map(Into::into)
85                .collect(),
86            metadata: module_data.metadata,
87        })
88    }
89
90    fn top_level_owner(&self, deps: Deps) -> StdResult<TopLevelOwnerResponse> {
91        let account = self.admin.get(deps)?.unwrap();
92        let addr = query_top_level_owner_addr(&deps.querier, account)?;
93        Ok(TopLevelOwnerResponse { address: addr })
94    }
95}
96
97#[cfg(test)]
98mod test {
99    #![allow(clippy::needless_borrows_for_generic_args)]
100    use abstract_sdk::base::QueryEndpoint;
101    use cosmwasm_std::{Binary, Deps, Env};
102
103    use super::QueryMsg as SuperQueryMsg;
104    use crate::mock::*;
105
106    type AppQueryMsg = SuperQueryMsg<MockQueryMsg>;
107
108    fn query_helper(deps: Deps, env: Env, msg: AppQueryMsg) -> Result<Binary, MockError> {
109        BASIC_MOCK_APP.query(deps, env, msg)
110    }
111
112    mod app_query {
113        use abstract_sdk::AbstractSdkError;
114        use abstract_testing::mock_env_validated;
115        use cosmwasm_std::{to_json_binary, Env};
116
117        use super::*;
118
119        #[coverage_helper::test]
120        fn without_handler() {
121            let deps = mock_init();
122            let msg = AppQueryMsg::Module(MockQueryMsg::GetSomething {});
123
124            let res = query_helper(deps.as_ref(), mock_env_validated(deps.api), msg);
125
126            assert!(matches!(
127                res,
128                Err(MockError::AbstractSdk(
129                    AbstractSdkError::MissingHandler { .. }
130                ))
131            ));
132        }
133
134        fn mock_query_handler(
135            _deps: Deps,
136            _env: Env,
137            _contract: &MockAppContract,
138            msg: MockQueryMsg,
139        ) -> Result<Binary, MockError> {
140            // simply return the message as binary
141            to_json_binary(&msg).map_err(Into::into)
142        }
143
144        #[coverage_helper::test]
145        fn with_handler() {
146            let deps = mock_init();
147            let msg = AppQueryMsg::Module(MockQueryMsg::GetSomething {});
148
149            let with_mocked_query = BASIC_MOCK_APP.with_query(mock_query_handler);
150            let res = with_mocked_query.query(deps.as_ref(), mock_env_validated(deps.api), msg);
151
152            let expected = to_json_binary(&MockQueryMsg::GetSomething {}).unwrap();
153            assert_eq!(res, Ok(expected));
154        }
155    }
156
157    mod base_query {
158        use super::*;
159
160        use abstract_std::{
161            app::{AppConfigResponse, BaseQueryMsg},
162            objects::module_version::ModuleDataResponse,
163        };
164        use abstract_testing::prelude::*;
165        use cw_controllers::AdminResponse;
166
167        #[coverage_helper::test]
168        fn config() -> AppTestResult {
169            let deps = mock_init();
170            let abstr = AbstractMockAddrs::new(deps.api);
171            let account = test_account(deps.api);
172
173            let config_query = QueryMsg::Base(BaseQueryMsg::BaseConfig {});
174            let res = query_helper(deps.as_ref(), mock_env_validated(deps.api), config_query)?;
175
176            assert_eq!(
177                AppConfigResponse {
178                    account: account.into_addr(),
179                    ans_host_address: abstr.ans_host,
180                    registry_address: abstr.registry,
181                },
182                from_json(res).unwrap()
183            );
184
185            Ok(())
186        }
187
188        #[coverage_helper::test]
189        fn admin() -> AppTestResult {
190            let deps = mock_init();
191            let account = test_account(deps.api);
192
193            let admin_query = QueryMsg::Base(BaseQueryMsg::BaseAdmin {});
194            let res = query_helper(deps.as_ref(), mock_env_validated(deps.api), admin_query)?;
195
196            assert_eq!(
197                AdminResponse {
198                    admin: Some(account.addr().to_string()),
199                },
200                from_json(res).unwrap()
201            );
202
203            Ok(())
204        }
205
206        #[coverage_helper::test]
207        fn module_data() -> AppTestResult {
208            let deps = mock_init();
209
210            let module_data_query = QueryMsg::Base(BaseQueryMsg::ModuleData {});
211            let res = query_helper(
212                deps.as_ref(),
213                mock_env_validated(deps.api),
214                module_data_query,
215            )?;
216
217            assert_eq!(
218                ModuleDataResponse {
219                    module_id: TEST_MODULE_ID.to_string(),
220                    version: TEST_VERSION.to_string(),
221                    dependencies: vec![],
222                    metadata: None
223                },
224                from_json(res).unwrap()
225            );
226
227            Ok(())
228        }
229    }
230}