abstract_std/objects/
registry.rs

1use cosmwasm_std::{Addr, Deps, QuerierWrapper};
2use thiserror::Error;
3
4use super::{
5    module::{Module, ModuleInfo},
6    module_reference::ModuleReference,
7    namespace::Namespace,
8    AccountId,
9};
10use crate::{
11    account::state::ACCOUNT_ID,
12    native_addrs,
13    registry::{
14        state::{
15            ACCOUNT_ADDRESSES, CONFIG, NAMESPACES, REGISTERED_MODULES, SERVICE_INFOS,
16            STANDALONE_INFOS,
17        },
18        Account, ModuleConfiguration, ModuleResponse, ModulesResponse, NamespaceResponse,
19        NamespacesResponse, QueryMsg,
20    },
21    AbstractResult,
22};
23
24#[derive(Error, Debug, PartialEq)]
25pub enum RegistryError {
26    // module not found in version registry
27    #[error("Module {module} not found in version registry {registry_addr}.")]
28    ModuleNotFound { module: String, registry_addr: Addr },
29
30    // failed to query account id
31    #[error("Failed to query Account id on contract {contract_addr}. Please ensure that the contract is an Account contract.")]
32    FailedToQueryAccountId { contract_addr: Addr },
33
34    // standalone module not found in version registry
35    #[error("Standalone {code_id} not found in version registry {registry_addr}.")]
36    StandaloneNotFound { code_id: u64, registry_addr: Addr },
37
38    // unknown Account id error
39    #[error("Unknown Account id {account_id} on registry {registry_addr}. Please ensure that you are using the correct Account id and registry address.")]
40    UnknownAccountId {
41        account_id: AccountId,
42        registry_addr: Addr,
43    },
44
45    // Caller is not a valid account
46    #[error("Address {0} is not the valid account address of {1}.")]
47    NotAccount(Addr, AccountId),
48
49    // Query method failed
50    #[error("Query during '{method_name}' failed: {error}")]
51    QueryFailed {
52        method_name: String,
53        error: cosmwasm_std::StdError,
54    },
55
56    // Service module not found in version registry
57    #[error("Service {service_addr} not found in version registry {registry_addr}.")]
58    ServiceNotFound {
59        service_addr: Addr,
60        registry_addr: Addr,
61    },
62
63    #[error("The provided module {0} has an invalid module reference.")]
64    InvalidReference(ModuleInfo),
65}
66
67pub type RegistryResult<T> = Result<T, RegistryError>;
68
69/// Store the Registry contract.
70#[allow(rustdoc::broken_intra_doc_links)]
71/// Implements [`AbstractRegistryAccess`] (defined in abstract-sdk)
72#[cosmwasm_schema::cw_serde]
73pub struct RegistryContract {
74    /// Address of the registry contract
75    pub address: Addr,
76}
77
78impl RegistryContract {
79    /// Retrieve address of the Registry
80    pub fn new(deps: Deps, abstract_code_id: u64) -> AbstractResult<Self> {
81        let address = deps
82            .api
83            .addr_humanize(&native_addrs::registry_address(deps, abstract_code_id)?)?;
84        Ok(Self { address })
85    }
86
87    // Module registry
88
89    /// Raw query for a module reference
90    #[function_name::named]
91    pub fn query_module_reference_raw(
92        &self,
93        module_info: &ModuleInfo,
94        querier: &QuerierWrapper,
95    ) -> RegistryResult<ModuleReference> {
96        let module_reference = REGISTERED_MODULES
97            .query(querier, self.address.clone(), module_info)
98            .map_err(|error| RegistryError::QueryFailed {
99                method_name: function_name!().to_owned(),
100                error,
101            })?;
102
103        module_reference.ok_or_else(|| RegistryError::ModuleNotFound {
104            module: module_info.to_string(),
105            registry_addr: self.address.clone(),
106        })
107    }
108
109    /// Smart query for a module
110    pub fn query_module(
111        &self,
112        module_info: ModuleInfo,
113        querier: &QuerierWrapper,
114    ) -> RegistryResult<Module> {
115        Ok(self
116            .query_modules_configs(vec![module_info], querier)?
117            .swap_remove(0)
118            .module)
119    }
120
121    /// Smart query for a module config
122    pub fn query_config(
123        &self,
124        module_info: ModuleInfo,
125        querier: &QuerierWrapper,
126    ) -> RegistryResult<ModuleConfiguration> {
127        Ok(self
128            .query_modules_configs(vec![module_info], querier)?
129            .swap_remove(0)
130            .config)
131    }
132
133    /// Smart query for a modules and its configurations
134    #[function_name::named]
135    pub fn query_modules_configs(
136        &self,
137        infos: Vec<ModuleInfo>,
138        querier: &QuerierWrapper,
139    ) -> RegistryResult<Vec<ModuleResponse>> {
140        let ModulesResponse { modules } = querier
141            .query_wasm_smart(self.address.to_string(), &QueryMsg::Modules { infos })
142            .map_err(|error| RegistryError::QueryFailed {
143                method_name: function_name!().to_owned(),
144                error,
145            })?;
146        Ok(modules)
147    }
148
149    /// Queries the account that owns the namespace
150    /// Is also returns the base modules of that account (Account)
151    #[function_name::named]
152    pub fn query_namespace(
153        &self,
154        namespace: Namespace,
155        querier: &QuerierWrapper,
156    ) -> RegistryResult<NamespaceResponse> {
157        let namespace_response: NamespaceResponse = querier
158            .query_wasm_smart(self.address.to_string(), &QueryMsg::Namespace { namespace })
159            .map_err(|error| RegistryError::QueryFailed {
160                method_name: function_name!().to_owned(),
161                error,
162            })?;
163        Ok(namespace_response)
164    }
165
166    /// Queries the account id that owns the namespace
167    #[function_name::named]
168    pub fn query_namespace_raw(
169        &self,
170        namespace: Namespace,
171        querier: &QuerierWrapper,
172    ) -> RegistryResult<Option<AccountId>> {
173        let namespace_response = NAMESPACES
174            .query(querier, self.address.clone(), &namespace)
175            .map_err(|error| RegistryError::QueryFailed {
176                method_name: function_name!().to_owned(),
177                error,
178            })?;
179        Ok(namespace_response)
180    }
181
182    /// Queries the namespaces owned by accounts
183    #[function_name::named]
184    pub fn query_namespaces(
185        &self,
186        accounts: Vec<AccountId>,
187        querier: &QuerierWrapper,
188    ) -> RegistryResult<NamespacesResponse> {
189        let namespaces_response: NamespacesResponse = querier
190            .query_wasm_smart(self.address.to_string(), &QueryMsg::Namespaces { accounts })
191            .map_err(|error| RegistryError::QueryFailed {
192                method_name: function_name!().to_owned(),
193                error,
194            })?;
195        Ok(namespaces_response)
196    }
197
198    /// Queries the module info of the standalone code id
199    #[function_name::named]
200    pub fn query_standalone_info_raw(
201        &self,
202        code_id: u64,
203        querier: &QuerierWrapper,
204    ) -> RegistryResult<ModuleInfo> {
205        let module_info = STANDALONE_INFOS
206            .query(querier, self.address.clone(), code_id)
207            .map_err(|error| RegistryError::QueryFailed {
208                method_name: function_name!().to_owned(),
209                error,
210            })?;
211        module_info.ok_or_else(|| RegistryError::StandaloneNotFound {
212            code_id,
213            registry_addr: self.address.clone(),
214        })
215    }
216
217    /// Queries the module info of the standalone code id
218    #[function_name::named]
219    pub fn query_service_info_raw(
220        &self,
221        service_addr: &Addr,
222        querier: &QuerierWrapper,
223    ) -> RegistryResult<ModuleInfo> {
224        let module_info = SERVICE_INFOS
225            .query(querier, self.address.clone(), service_addr)
226            .map_err(|error| RegistryError::QueryFailed {
227                method_name: function_name!().to_owned(),
228                error,
229            })?;
230        module_info.ok_or_else(|| RegistryError::ServiceNotFound {
231            service_addr: service_addr.clone(),
232            registry_addr: self.address.clone(),
233        })
234    }
235
236    // AccountRegistry
237
238    /// Get self reported Account id, for checked use
239    /// [`RegistryContract::account_id`]
240    pub fn unchecked_account_id(
241        &self,
242        maybe_core_contract_addr: &Addr,
243        querier: &QuerierWrapper,
244    ) -> RegistryResult<AccountId> {
245        ACCOUNT_ID
246            .query(querier, maybe_core_contract_addr.clone())
247            .map_err(|_| RegistryError::FailedToQueryAccountId {
248                contract_addr: maybe_core_contract_addr.clone(),
249            })
250    }
251
252    /// Get AccountId for given account address.
253    /// Also verifies that that address is indeed an account.
254    pub fn account_id(
255        &self,
256        maybe_account_addr: &Addr,
257        querier: &QuerierWrapper,
258    ) -> RegistryResult<AccountId> {
259        let self_reported_account_id = self.unchecked_account_id(maybe_account_addr, querier)?;
260        // now we need to verify that the account id is indeed correct
261        let account = self.account(&self_reported_account_id, querier)?;
262        if account.addr().ne(maybe_account_addr) {
263            Err(RegistryError::FailedToQueryAccountId {
264                contract_addr: maybe_account_addr.clone(),
265            })
266        } else {
267            Ok(self_reported_account_id)
268        }
269    }
270
271    /// Get the account for a given account id.
272    #[function_name::named]
273    pub fn account(
274        &self,
275        account_id: &AccountId,
276        querier: &QuerierWrapper,
277    ) -> RegistryResult<Account> {
278        let maybe_account = ACCOUNT_ADDRESSES
279            .query(querier, self.address.clone(), account_id)
280            .map_err(|error| RegistryError::QueryFailed {
281                method_name: function_name!().to_owned(),
282                error,
283            })?;
284        maybe_account.ok_or_else(|| RegistryError::UnknownAccountId {
285            account_id: account_id.clone(),
286            registry_addr: self.address.clone(),
287        })
288    }
289
290    /// Get namespace registration fee
291    #[function_name::named]
292    pub fn namespace_registration_fee(
293        &self,
294        querier: &QuerierWrapper,
295    ) -> RegistryResult<Option<cosmwasm_std::Coin>> {
296        let config = CONFIG
297            .query(querier, self.address.clone())
298            .map_err(|error| RegistryError::QueryFailed {
299                method_name: function_name!().to_owned(),
300                error,
301            })?;
302        Ok(config.namespace_registration_fee)
303    }
304
305    /// Verify if the provided account address is indeed a user.
306    pub fn assert_account(
307        &self,
308        maybe_account: &Addr,
309        querier: &QuerierWrapper,
310    ) -> RegistryResult<Account> {
311        let account_id = self.unchecked_account_id(maybe_account, querier)?;
312        let account = self.account(&account_id, querier)?;
313        if account.addr().ne(maybe_account) {
314            Err(RegistryError::NotAccount(maybe_account.clone(), account_id))
315        } else {
316            Ok(account)
317        }
318    }
319}