1pub use abstract_std::registry::{
2 ExecuteMsgFns as RegistryExecFns, QueryMsgFns as RegistryQueryFns,
3};
4use abstract_std::{
5 objects::{
6 dependency::StaticDependency,
7 module::{Module, ModuleId, ModuleInfo, ModuleStatus, ModuleVersion},
8 module_reference::ModuleReference,
9 namespace::{Namespace, ABSTRACT_NAMESPACE},
10 AccountId,
11 },
12 registry::*,
13 REGISTRY,
14};
15use cw_orch::{contract::Contract, interface, prelude::*};
16
17use crate::AccountI;
18
19type VersionString = String;
20
21#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, MigrateMsg)]
22pub struct Registry<Chain>;
23
24impl<Chain: CwEnv> cw_blob::interface::DeterministicInstantiation<Chain> for Registry<Chain> {}
25
26impl<Chain: CwEnv> Uploadable for Registry<Chain> {
27 fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
28 Box::new(
29 ContractWrapper::new_with_empty(
30 ::registry::contract::execute,
31 ::registry::contract::instantiate,
32 ::registry::contract::query,
33 )
34 .with_migrate(::registry::migrate::migrate),
35 )
36 }
37 fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
38 artifacts_dir_from_workspace!()
39 .find_wasm_path("registry")
40 .unwrap()
41 }
42}
43
44impl<Chain: CwEnv> Registry<Chain> {
45 pub fn load(chain: Chain, address: &Addr) -> Self {
46 let contract = cw_orch::contract::Contract::new(REGISTRY, chain);
47 contract.set_address(address);
48 Self(contract)
49 }
50
51 pub fn module(&self, info: ModuleInfo) -> Result<Module, crate::AbstractInterfaceError> {
53 let ModulesResponse { mut modules } = self.modules(vec![info])?;
54
55 Ok(modules.swap_remove(0).module)
56 }
57
58 pub fn registered_or_pending_module(
60 &self,
61 info: ModuleInfo,
62 ) -> Result<Module, crate::AbstractInterfaceError> {
63 let mut module_list_response = self.module_list(
64 Some(ModuleFilter {
65 namespace: Some(info.namespace.to_string()),
66 name: Some(info.name.clone()),
67 version: Some(info.version.to_string()),
68 status: Some(ModuleStatus::Registered),
69 }),
70 None,
71 None,
72 )?;
73
74 if !module_list_response.modules.is_empty() {
75 Ok(module_list_response.modules.swap_remove(0).module)
77 } else {
78 let mut module_list_response = self.module_list(
79 Some(ModuleFilter {
80 namespace: Some(info.namespace.to_string()),
81 name: Some(info.name),
82 version: Some(info.version.to_string()),
83 status: Some(ModuleStatus::Pending),
84 }),
85 None,
86 None,
87 )?;
88 if !module_list_response.modules.is_empty() {
89 Ok(module_list_response.modules.swap_remove(0).module)
90 } else {
91 Err(crate::AbstractInterfaceError::Std(
92 cosmwasm_std::StdError::generic_err("Module not found"),
93 ))
94 }
95 }
96 }
97
98 pub fn module_status(
100 &self,
101 info: ModuleInfo,
102 ) -> Result<Option<ModuleStatus>, crate::AbstractInterfaceError> {
103 let is_module_status = |m: ModuleStatus| -> Result<bool, crate::AbstractInterfaceError> {
104 let is_module_status = !self
105 .module_list(
106 Some(ModuleFilter {
107 namespace: Some(info.namespace.to_string()),
108 name: Some(info.name.clone()),
109 version: Some(info.version.to_string()),
110 status: Some(m),
111 }),
112 None,
113 None,
114 )?
115 .modules
116 .is_empty();
117 Ok(is_module_status)
118 };
119
120 if is_module_status(ModuleStatus::Registered)? {
121 Ok(Some(ModuleStatus::Registered))
122 } else if is_module_status(ModuleStatus::Pending)? {
123 Ok(Some(ModuleStatus::Pending))
124 } else if is_module_status(ModuleStatus::Yanked)? {
125 Ok(Some(ModuleStatus::Yanked))
126 } else {
127 Ok(None)
129 }
130 }
131
132 pub fn module_versions(
134 &self,
135 module_id: ModuleId,
136 ) -> Result<Vec<semver::Version>, crate::AbstractInterfaceError> {
137 let parts: Vec<&str> = module_id.split(':').collect();
138 if parts.len() != 2 {
139 return Err(abstract_std::AbstractError::FormattingError {
140 object: "module_id".to_string(),
141 expected: "namespace:module".to_string(),
142 actual: module_id.to_string(),
143 }
144 .into());
145 }
146
147 let mut start_after = None;
148 let mut versions: Vec<semver::Version> = vec![];
149 loop {
150 let modules_page = self
151 .module_list(
152 Some(ModuleFilter {
153 namespace: Some(parts[0].to_owned()),
154 name: Some(parts[1].to_owned()),
155 version: None,
156 status: Some(ModuleStatus::Registered),
157 }),
158 None,
159 start_after,
160 )?
161 .modules;
162 if modules_page.is_empty() {
163 break;
164 }
165 start_after = modules_page.last().map(|module| module.module.info.clone());
166 let versions_page = modules_page
167 .into_iter()
168 .map(|module| module.module.info.version.try_into().unwrap());
169
170 versions.extend(versions_page)
171 }
172 Ok(versions)
173 }
174
175 pub fn assert_dependencies_deployed(
177 &self,
178 dependencies: &[StaticDependency],
179 ) -> Result<(), crate::AbstractInterfaceError> {
180 for dependency in dependencies {
181 let module_versions = self.module_versions(dependency.id)?;
182 let matches = module_versions
184 .iter()
185 .any(|version| dependency.matches(version));
186 if !matches {
187 return Err(crate::AbstractInterfaceError::NoMatchingModule(
188 dependency.clone(),
189 ));
190 }
191 }
192 Ok(())
193 }
194
195 pub fn register_base(
196 &self,
197 account: &AccountI<Chain>,
198 ) -> Result<(), crate::AbstractInterfaceError> {
199 let account = account.as_instance();
200 let account_module = (
201 ModuleInfo::from_id(
202 &account.id,
203 ModuleVersion::Version(account::contract::CONTRACT_VERSION.to_string()),
204 )?,
205 ModuleReference::Account(account.code_id()?),
206 );
207 self.propose_modules(vec![account_module])?;
208
209 log::info!("Module {} registered", account.id);
210 Ok(())
211 }
212
213 pub fn register_account(
215 &self,
216 account: &Contract<Chain>,
217 version: VersionString,
218 ) -> Result<(), crate::AbstractInterfaceError> {
219 let to_register = self.contracts_into_module_entries(vec![(account, version)], |c| {
220 ModuleReference::Account(c.code_id().unwrap())
221 })?;
222 self.propose_modules(to_register)?;
223 Ok(())
224 }
225
226 pub fn register_natives(
228 &self,
229 natives: Vec<(&Contract<Chain>, VersionString)>,
230 ) -> Result<(), crate::AbstractInterfaceError> {
231 let to_register = self.contracts_into_module_entries(natives, |c| {
232 ModuleReference::Native(c.address().unwrap())
233 })?;
234 let to_register_module_ids = to_register
235 .iter()
236 .map(|to_register| to_register.0.id())
237 .collect::<Vec<String>>()
238 .join(",");
239 log::info!("Modules {to_register_module_ids} registered");
240 self.propose_modules(to_register)?;
241 Ok(())
242 }
243
244 pub fn register_services(
246 &self,
247 services: Vec<(&Contract<Chain>, VersionString)>,
248 ) -> Result<(), crate::AbstractInterfaceError> {
249 let to_register = self.contracts_into_module_entries(services, |c| {
250 ModuleReference::Service(c.address().unwrap())
251 })?;
252 self.propose_modules(to_register)?;
253 Ok(())
254 }
255
256 pub fn register_apps(
257 &self,
258 apps: Vec<(&Contract<Chain>, VersionString)>,
259 ) -> Result<(), crate::AbstractInterfaceError> {
260 let to_register = self
261 .contracts_into_module_entries(apps, |c| ModuleReference::App(c.code_id().unwrap()))?;
262 self.propose_modules(to_register)?;
263 Ok(())
264 }
265
266 pub fn register_adapters(
267 &self,
268 adapters: Vec<(&Contract<Chain>, VersionString)>,
269 ) -> Result<(), crate::AbstractInterfaceError> {
270 let to_register = self.contracts_into_module_entries(adapters, |c| {
271 ModuleReference::Adapter(c.address().unwrap())
272 })?;
273 self.propose_modules(to_register)?;
274 Ok(())
275 }
276
277 pub fn register_standalones(
278 &self,
279 standalones: Vec<(&Contract<Chain>, VersionString)>,
280 ) -> Result<(), crate::AbstractInterfaceError> {
281 let to_register = self.contracts_into_module_entries(standalones, |c| {
282 ModuleReference::Standalone(c.code_id().unwrap())
283 })?;
284 self.propose_modules(to_register)?;
285 Ok(())
286 }
287
288 pub fn approve_any_abstract_modules(&self) -> Result<(), crate::AbstractInterfaceError> {
290 self.approve_all_modules_for_namespace(Namespace::unchecked(ABSTRACT_NAMESPACE))
291 }
292
293 pub fn approve_all_modules_for_namespace(
295 &self,
296 namespace: Namespace,
297 ) -> Result<(), crate::AbstractInterfaceError> {
298 let proposed_namespace_modules = self.module_list(
299 Some(ModuleFilter {
300 namespace: Some(namespace.to_string()),
301 status: Some(ModuleStatus::Pending),
302 ..Default::default()
303 }),
304 None,
305 None,
306 )?;
307
308 if proposed_namespace_modules.modules.is_empty() {
309 return Ok(());
310 }
311
312 self.approve_or_reject_modules(
313 proposed_namespace_modules
314 .modules
315 .into_iter()
316 .map(|m| m.module.info)
317 .collect(),
318 vec![],
319 )?;
320 Ok(())
321 }
322
323 fn contracts_into_module_entries<RefFn>(
324 &self,
325 modules: Vec<(&Contract<Chain>, VersionString)>,
326 ref_fn: RefFn,
327 ) -> Result<Vec<(ModuleInfo, ModuleReference)>, crate::AbstractInterfaceError>
328 where
329 RefFn: Fn(&&Contract<Chain>) -> ModuleReference,
330 {
331 let modules_to_register: Result<
332 Vec<(ModuleInfo, ModuleReference)>,
333 crate::AbstractInterfaceError,
334 > = modules
335 .iter()
336 .map(|(contract, version)| {
337 Ok((
338 ModuleInfo::from_id(&contract.id, ModuleVersion::Version(version.to_owned()))?,
339 ref_fn(contract),
340 ))
341 })
342 .collect();
343 modules_to_register
344 }
345
346 pub fn account(&self, account_id: AccountId) -> Result<Account, crate::AbstractInterfaceError> {
347 let resp: AccountsResponse = self.accounts(vec![account_id.clone()])?;
348 Ok(resp.accounts[0].clone())
350 }
351
352 pub fn get_adapter_addr(
354 &self,
355 id: &str,
356 version: ModuleVersion,
357 ) -> Result<Addr, crate::AbstractInterfaceError> {
358 let module: Module = self.module(ModuleInfo::from_id(id, version)?)?;
359
360 Ok(module.reference.unwrap_adapter()?)
361 }
362
363 pub fn get_app_code(
365 &self,
366 id: &str,
367 version: ModuleVersion,
368 ) -> Result<u64, crate::AbstractInterfaceError> {
369 let module: Module = self.module(ModuleInfo::from_id(id, version)?)?;
370
371 Ok(module.reference.unwrap_app()?)
372 }
373
374 pub fn get_standalone_code(
376 &self,
377 id: &str,
378 version: ModuleVersion,
379 ) -> Result<u64, crate::AbstractInterfaceError> {
380 let module: Module = self.module(ModuleInfo::from_id(id, version)?)?;
381
382 Ok(module.reference.unwrap_standalone()?)
383 }
384
385 pub fn get_account_code(&self) -> Result<u64, crate::AbstractInterfaceError> {
387 let module: Module = self.module(ModuleInfo::from_id_latest(abstract_std::ACCOUNT)?)?;
388
389 Ok(module.reference.unwrap_account()?)
390 }
391}
392
393impl Registry<Mock> {
394 pub fn approve_any_modules(&self) -> Result<(), crate::AbstractInterfaceError> {
396 let proposed_abstract_modules = self.module_list(
397 Some(ModuleFilter {
398 status: Some(ModuleStatus::Pending),
399 ..Default::default()
400 }),
401 None,
402 None,
403 )?;
404
405 if proposed_abstract_modules.modules.is_empty() {
406 return Ok(());
407 }
408
409 let owner = self.ownership()?;
410 self.call_as(&Addr::unchecked(owner.owner.unwrap()))
411 .approve_or_reject_modules(
412 proposed_abstract_modules
413 .modules
414 .iter()
415 .map(|m| m.module.info.clone())
416 .collect(),
417 vec![],
418 )?;
419 Ok(())
420 }
421}