1use abstract_sdk::{
2 cw_helpers::Clearable,
3 std::{
4 objects::{
5 module::{ModuleInfo, ModuleVersion},
6 module_reference::ModuleReference,
7 namespace::Namespace,
8 AccountId,
9 },
10 version_control::{state::*, AccountBase, Config},
11 },
12};
13use abstract_std::{
14 objects::{
15 fee::FixedFee,
16 module::{self, Module},
17 ownership,
18 validation::validate_link,
19 ABSTRACT_ACCOUNT_ID,
20 },
21 version_control::{ModuleDefaultConfiguration, UpdateModule},
22};
23use cosmwasm_std::{
24 ensure, Addr, Attribute, BankMsg, Coin, CosmosMsg, Deps, DepsMut, MessageInfo, Order,
25 QuerierWrapper, StdResult, Storage,
26};
27
28use crate::{
29 contract::{VCResult, VcResponse, ABSTRACT_NAMESPACE},
30 error::VCError,
31};
32
33pub fn add_account(
36 deps: DepsMut,
37 msg_info: MessageInfo,
38 account_id: AccountId,
39 account_base: AccountBase,
40 namespace: Option<String>,
41) -> VCResult {
42 let config = CONFIG.load(deps.storage)?;
43
44 let is_factory = config
46 .account_factory_address
47 .map(|addr| addr == msg_info.sender)
48 .unwrap_or(false);
49 if !is_factory {
50 return Err(VCError::NotAccountFactory {});
51 }
52
53 ensure!(
55 !ACCOUNT_ADDRESSES.has(deps.storage, &account_id),
56 VCError::AccountAlreadyExists(account_id)
57 );
58
59 ACCOUNT_ADDRESSES.save(deps.storage, &account_id, &account_base)?;
60
61 let fee_msg = if let Some(namespace) = &namespace {
62 claim_namespace_internal(
63 deps.storage,
64 config.namespace_registration_fee,
65 msg_info,
66 account_id.clone(),
67 namespace,
68 )?
69 } else {
70 None
71 };
72
73 let mut response = VcResponse::new(
74 "add_account",
75 vec![
76 ("account_id", account_id.to_string().as_str()),
77 ("manager", account_base.manager.as_ref()),
78 ("proxy", account_base.proxy.as_ref()),
79 ("namespace", &format!("{namespace:?}")),
80 ],
81 );
82
83 if let Some(msg) = fee_msg {
84 response = response.add_message(msg);
85 }
86 Ok(response)
87}
88
89pub fn propose_modules(
91 deps: DepsMut,
92 msg_info: MessageInfo,
93 modules: Vec<(ModuleInfo, ModuleReference)>,
94) -> VCResult {
95 let config = CONFIG.load(deps.storage)?;
96
97 for (module, mod_ref) in modules {
98 let store_has_module = PENDING_MODULES.has(deps.storage, &module)
99 || REGISTERED_MODULES.has(deps.storage, &module)
100 || YANKED_MODULES.has(deps.storage, &module);
101 if !config.security_disabled && store_has_module {
102 return Err(VCError::NotUpdateableModule(module));
103 }
104
105 module.validate()?;
106
107 mod_ref.validate(deps.as_ref())?;
108
109 module.assert_version_variant()?;
111
112 if module.namespace == Namespace::unchecked(ABSTRACT_NAMESPACE) {
113 cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
115 } else {
116 validate_account_owner(deps.as_ref(), &module.namespace, &msg_info.sender)?;
118 }
119
120 if let ModuleReference::Adapter(ref addr) = mod_ref {
122 if deps.querier.query_wasm_contract_info(addr)?.admin.is_some() {
123 return Err(VCError::AdminMustBeNone);
124 }
125 }
126
127 if config.security_disabled {
128 module::assert_module_data_validity(
130 &deps.querier,
131 &Module {
132 info: module.clone(),
133 reference: mod_ref.clone(),
134 },
135 None,
136 )?;
137 REGISTERED_MODULES.save(deps.storage, &module, &mod_ref)?;
138 if let ModuleReference::Standalone(id) = mod_ref {
141 STANDALONE_INFOS.save(deps.storage, id, &module)?;
142 }
143 } else {
144 PENDING_MODULES.save(deps.storage, &module, &mod_ref)?;
145 }
146 }
147
148 Ok(VcResponse::action("propose_modules"))
149}
150
151pub fn approve_or_reject_modules(
153 deps: DepsMut,
154 msg_info: MessageInfo,
155 approves: Vec<ModuleInfo>,
156 rejects: Vec<ModuleInfo>,
157) -> VCResult {
158 cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
160
161 let mut attributes = vec![];
162 if !approves.is_empty() {
163 attributes.push(approve_modules(deps.storage, approves)?);
164 }
165 if !rejects.is_empty() {
166 attributes.push(reject_modules(deps.storage, rejects)?);
167 }
168 if attributes.is_empty() {
169 return Err(VCError::NoAction);
170 }
171
172 Ok(VcResponse::new("approve_or_reject_modules", attributes))
173}
174
175fn approve_modules(storage: &mut dyn Storage, approves: Vec<ModuleInfo>) -> VCResult<Attribute> {
177 for module in &approves {
178 let mod_ref = PENDING_MODULES
179 .may_load(storage, module)?
180 .ok_or_else(|| VCError::ModuleNotFound(module.clone()))?;
181 REGISTERED_MODULES.save(storage, module, &mod_ref)?;
183 PENDING_MODULES.remove(storage, module);
185
186 if let ModuleReference::Standalone(id) = mod_ref {
189 STANDALONE_INFOS.save(storage, id, module)?;
190 }
191 }
192
193 let approves: Vec<_> = approves.into_iter().map(|m| m.to_string()).collect();
194 Ok(("approves", approves.join(",")).into())
195}
196
197fn reject_modules(storage: &mut dyn Storage, rejects: Vec<ModuleInfo>) -> VCResult<Attribute> {
199 for module in &rejects {
200 if !PENDING_MODULES.has(storage, module) {
201 return Err(VCError::ModuleNotFound(module.clone()));
202 }
203 PENDING_MODULES.remove(storage, module);
204 }
205
206 let rejects: Vec<_> = rejects.into_iter().map(|m| m.to_string()).collect();
207 Ok(("rejects", rejects.join(",")).into())
208}
209
210pub fn remove_module(deps: DepsMut, msg_info: MessageInfo, module: ModuleInfo) -> VCResult {
212 cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
214
215 module.assert_version_variant()?;
217
218 let module_ref_res = REGISTERED_MODULES.load(deps.storage, &module);
219
220 ensure!(
221 module_ref_res.is_ok() || YANKED_MODULES.has(deps.storage, &module),
222 VCError::ModuleNotFound(module)
223 );
224
225 REGISTERED_MODULES.remove(deps.storage, &module);
226 YANKED_MODULES.remove(deps.storage, &module);
227 MODULE_CONFIG.remove(deps.storage, &module);
228
229 if let Ok(ModuleReference::Standalone(id)) = module_ref_res {
231 STANDALONE_INFOS.remove(deps.storage, id);
232 }
233
234 if REGISTERED_MODULES
236 .prefix((module.namespace.clone(), module.name.clone()))
237 .range(deps.storage, None, None, Order::Ascending)
238 .next()
239 .is_none()
240 {
241 MODULE_DEFAULT_CONFIG.remove(deps.storage, (&module.namespace, &module.name));
242 }
243 Ok(VcResponse::new(
244 "remove_module",
245 vec![("module", &module.to_string())],
246 ))
247}
248
249pub fn yank_module(deps: DepsMut, msg_info: MessageInfo, module: ModuleInfo) -> VCResult {
251 validate_account_owner(deps.as_ref(), &module.namespace, &msg_info.sender)?;
253
254 module.assert_version_variant()?;
256 let mod_ref = REGISTERED_MODULES
257 .may_load(deps.storage, &module)?
258 .ok_or_else(|| VCError::ModuleNotFound(module.clone()))?;
259
260 YANKED_MODULES.save(deps.storage, &module, &mod_ref)?;
261 REGISTERED_MODULES.remove(deps.storage, &module);
262
263 Ok(VcResponse::new(
264 "yank_module",
265 vec![("module", &module.to_string())],
266 ))
267}
268
269pub fn update_module_config(
271 deps: DepsMut,
272 msg_info: MessageInfo,
273 module_name: String,
274 namespace: Namespace,
275 update_module: UpdateModule,
276) -> VCResult {
277 if namespace == Namespace::unchecked(ABSTRACT_NAMESPACE) {
280 cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
282 } else {
283 validate_account_owner(deps.as_ref(), &namespace, &msg_info.sender)?;
285 }
286
287 match update_module {
288 UpdateModule::Default { metadata } => {
289 if REGISTERED_MODULES
291 .prefix((namespace.clone(), module_name.clone()))
292 .range(deps.storage, None, None, Order::Ascending)
293 .next()
294 .is_none()
295 {
296 return Err(VCError::ModuleNotFound(ModuleInfo {
297 namespace,
298 name: module_name,
299 version: ModuleVersion::Latest,
300 }));
301 }
302
303 validate_link(Some(&metadata))?;
304
305 MODULE_DEFAULT_CONFIG.save(
306 deps.storage,
307 (&namespace, &module_name),
308 &ModuleDefaultConfiguration::new(metadata),
309 )?;
310 }
311 UpdateModule::Versioned {
312 version,
313 metadata,
314 monetization,
315 instantiation_funds,
316 } => {
317 let module = ModuleInfo {
318 namespace: namespace.clone(),
319 name: module_name.clone(),
320 version: ModuleVersion::Version(version),
321 };
322
323 let Some(module_reference) = REGISTERED_MODULES.may_load(deps.storage, &module)? else {
325 return Err(VCError::ModuleNotFound(module));
326 };
327
328 let mut current_cfg = MODULE_CONFIG
329 .may_load(deps.storage, &module)?
330 .unwrap_or_default();
331 if let Some(metadata) = metadata {
333 current_cfg.metadata = Some(metadata);
334 }
335
336 if let Some(monetization) = monetization {
338 current_cfg.monetization = monetization;
339 }
340
341 if let Some(init_funds) = instantiation_funds {
343 if matches!(
344 module_reference,
345 ModuleReference::App(_) | ModuleReference::Standalone(_)
346 ) {
347 current_cfg.instantiation_funds = init_funds
348 } else {
349 return Err(VCError::RedundantInitFunds {});
350 }
351 }
352 MODULE_CONFIG.save(deps.storage, &module, ¤t_cfg)?;
353 }
354 _ => todo!(),
355 };
356
357 Ok(VcResponse::new(
358 "update_module_config",
359 vec![
360 ("namespace", &namespace.to_string()),
361 ("module_name", &module_name),
362 ],
363 ))
364}
365
366pub fn claim_namespace(
369 deps: DepsMut,
370 msg_info: MessageInfo,
371 account_id: AccountId,
372 namespace_to_claim: String,
373) -> VCResult {
374 let Config {
375 namespace_registration_fee: fee,
376 security_disabled,
377 ..
378 } = CONFIG.load(deps.storage)?;
379
380 if !security_disabled {
381 cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
383 } else {
384 let account_base = ACCOUNT_ADDRESSES.load(deps.storage, &account_id)?;
386 let account_owner = query_account_owner(&deps.querier, account_base.manager, &account_id)?;
387
388 if msg_info.sender != account_owner {
390 return Err(VCError::AccountOwnerMismatch {
391 sender: msg_info.sender,
392 owner: account_owner,
393 });
394 }
395 }
396
397 let fee_msg = claim_namespace_internal(
398 deps.storage,
399 fee,
400 msg_info,
401 account_id.clone(),
402 &namespace_to_claim,
403 )?;
404
405 let mut response = VcResponse::new(
406 "claim_namespace",
407 vec![
408 ("account_id", account_id.to_string()),
409 ("namespaces", namespace_to_claim),
410 ],
411 );
412
413 if let Some(msg) = fee_msg {
414 response = response.add_message(msg);
415 }
416 Ok(response)
417}
418
419fn claim_namespace_internal(
421 storage: &mut dyn Storage,
422 fee: Option<Coin>,
423 msg_info: MessageInfo,
424 account_id: AccountId,
425 namespace_to_claim: &str,
426) -> VCResult<Option<CosmosMsg>> {
427 let has_namespace = NAMESPACES_INFO
429 .idx
430 .account_id
431 .prefix(account_id.clone())
432 .range(storage, None, None, Order::Ascending)
433 .take(1)
434 .count()
435 == 1;
436 if has_namespace {
437 return Err(VCError::ExceedsNamespaceLimit {
438 limit: 1,
439 current: 1,
440 });
441 }
442
443 let fee_msg = if let Some(fee) = fee {
444 FixedFee::new(&fee).assert_payment(&msg_info)?;
446
447 let admin_account = ACCOUNT_ADDRESSES.load(storage, &ABSTRACT_ACCOUNT_ID)?;
449 Some(CosmosMsg::Bank(BankMsg::Send {
450 to_address: admin_account.proxy.to_string(),
451 amount: msg_info.funds,
452 }))
453 } else {
454 None
455 };
456
457 let namespace = Namespace::try_from(namespace_to_claim)?;
458 if let Some(id) = NAMESPACES_INFO.may_load(storage, &namespace)? {
459 return Err(VCError::NamespaceOccupied {
460 namespace: namespace.to_string(),
461 id,
462 });
463 }
464 NAMESPACES_INFO.save(storage, &namespace, &account_id)?;
465
466 Ok(fee_msg)
467}
468
469pub fn remove_namespaces(
472 deps: DepsMut,
473 msg_info: MessageInfo,
474 namespaces: Vec<String>,
475) -> VCResult {
476 let is_admin = cw_ownable::is_owner(deps.storage, &msg_info.sender)?;
477
478 let mut logs = vec![];
479 for namespace in namespaces.iter() {
480 let namespace = Namespace::try_from(namespace)?;
481 if !NAMESPACES_INFO.has(deps.storage, &namespace) {
482 return Err(VCError::UnknownNamespace { namespace });
483 }
484 if !is_admin {
485 validate_account_owner(deps.as_ref(), &namespace, &msg_info.sender)?;
486 }
487
488 for ((name, version), mod_ref) in REGISTERED_MODULES
489 .sub_prefix(namespace.clone())
490 .range(deps.storage, None, None, Order::Ascending)
491 .collect::<StdResult<Vec<_>>>()?
492 .into_iter()
493 {
494 let module = ModuleInfo {
495 namespace: namespace.clone(),
496 name,
497 version: ModuleVersion::Version(version),
498 };
499 REGISTERED_MODULES.remove(deps.storage, &module);
500 YANKED_MODULES.save(deps.storage, &module, &mod_ref)?;
501 }
502
503 logs.push(format!(
504 "({}, {})",
505 namespace,
506 NAMESPACES_INFO.load(deps.storage, &namespace)?
507 ));
508 NAMESPACES_INFO.remove(deps.storage, &namespace)?;
509 }
510
511 Ok(VcResponse::new(
512 "remove_namespaces",
513 vec![("namespaces", &logs.join(","))],
514 ))
515}
516
517pub fn update_config(
518 deps: DepsMut,
519 info: MessageInfo,
520 account_factory_address: Option<String>,
521 security_disabled: Option<bool>,
522 namespace_registration_fee: Option<Clearable<Coin>>,
523) -> VCResult {
524 cw_ownable::assert_owner(deps.storage, &info.sender)?;
525 let mut config = CONFIG.load(deps.storage)?;
526
527 let mut attributes = vec![];
528
529 if let Some(allow) = security_disabled {
530 let previous_allow = config.security_disabled;
531 config.security_disabled = allow;
532 attributes.extend(vec![
533 ("previous_security_disabled", previous_allow.to_string()),
534 (
535 "allow_direct_module_registration_and_updates",
536 allow.to_string(),
537 ),
538 ])
539 }
540
541 if let Some(fee) = namespace_registration_fee {
542 let previous_fee = config.namespace_registration_fee;
543 let fee: Option<Coin> = fee.into();
544 config.namespace_registration_fee = fee;
545 attributes.extend(vec![
546 (
547 "previous_namespace_registration_fee",
548 format!("{:?}", previous_fee),
549 ),
550 (
551 "namespace_registration_fee",
552 format!("{:?}", config.namespace_registration_fee),
553 ),
554 ])
555 }
556
557 if let Some(account_factory) = account_factory_address {
558 let previous_addr = config.account_factory_address;
559
560 let addr = deps.api.addr_validate(&account_factory)?;
561 config.account_factory_address = Some(addr);
562 attributes.extend(vec![
563 ("previous_account_factory", format!("{previous_addr:?}")),
564 ("account_factory", account_factory),
565 ])
566 }
567
568 CONFIG.save(deps.storage, &config)?;
569
570 Ok(VcResponse::new("update_config", attributes))
571}
572
573pub fn query_account_owner(
574 querier: &QuerierWrapper,
575 manager_addr: Addr,
576 account_id: &AccountId,
577) -> VCResult<Addr> {
578 let ownership::Ownership { owner, .. } = ownership::query_ownership(querier, manager_addr)?;
579
580 owner
581 .owner_address(querier)
582 .ok_or_else(|| VCError::NoAccountOwner {
583 account_id: account_id.clone(),
584 })
585}
586
587pub fn validate_account_owner(
588 deps: Deps,
589 namespace: &Namespace,
590 sender: &Addr,
591) -> Result<(), VCError> {
592 let sender = sender.clone();
593 let account_id = NAMESPACES_INFO
594 .may_load(deps.storage, &namespace.clone())?
595 .ok_or_else(|| VCError::UnknownNamespace {
596 namespace: namespace.to_owned(),
597 })?;
598 let account_base = ACCOUNT_ADDRESSES.load(deps.storage, &account_id)?;
599 let manager = account_base.manager;
600 if sender != manager {
602 let account_owner = query_account_owner(&deps.querier, manager.clone(), &account_id)?;
603 if sender != account_owner {
604 return Err(VCError::AccountOwnerMismatch {
605 sender,
606 owner: account_owner,
607 });
608 }
609 }
610 Ok(())
611}
612
613#[cfg(test)]
614mod test {
615 use abstract_std::{
616 manager::{ConfigResponse as ManagerConfigResponse, QueryMsg as ManagerQueryMsg},
617 objects::account::AccountTrace,
618 version_control::*,
619 };
620 use abstract_testing::{prelude::*, MockQuerierOwnership};
621 use cosmwasm_std::{
622 from_json,
623 testing::{mock_dependencies, mock_env, mock_info},
624 to_json_binary, Addr, Coin,
625 };
626 use cw_ownable::OwnershipError;
627 use speculoos::prelude::*;
628
629 use super::*;
630 use crate::{contract, testing::*};
631
632 type VersionControlTestResult = Result<(), VCError>;
633
634 const TEST_OTHER: &str = "test-other";
635 pub const SECOND_TEST_ACCOUNT_ID: AccountId = AccountId::const_new(2, AccountTrace::Local);
636
637 pub fn mock_manager_querier() -> MockQuerierBuilder {
638 MockQuerierBuilder::default()
639 .with_smart_handler(TEST_MANAGER, |msg| {
640 match from_json(msg).unwrap() {
641 ManagerQueryMsg::Config {} => {
642 let resp = ManagerConfigResponse {
643 version_control_address: Addr::unchecked(TEST_VERSION_CONTROL),
644 module_factory_address: Addr::unchecked(TEST_MODULE_FACTORY),
645 account_id: TEST_ACCOUNT_ID, is_suspended: false,
647 };
648 Ok(to_json_binary(&resp).unwrap())
649 }
650 ManagerQueryMsg::Ownership {} => {
651 let resp = ownership::Ownership {
652 owner: ownership::GovernanceDetails::Monarchy {
653 monarch: Addr::unchecked(OWNER),
654 },
655 pending_expiry: None,
656 pending_owner: None,
657 };
658 Ok(to_json_binary(&resp).unwrap())
659 }
660 _ => panic!("unexpected message"),
661 }
662 })
663 .with_owner(TEST_MANAGER, Some(OWNER))
664 }
665
666 fn mock_init_with_factory(mut deps: DepsMut) -> VCResult {
668 let info = mock_info(OWNER, &[]);
669 let admin = info.sender.to_string();
670
671 contract::instantiate(
672 deps.branch(),
673 mock_env(),
674 info,
675 InstantiateMsg {
676 admin,
677 security_disabled: Some(true),
678 namespace_registration_fee: None,
679 },
680 )?;
681 execute_as_admin(
682 deps,
683 ExecuteMsg::UpdateConfig {
684 account_factory_address: Some(TEST_ACCOUNT_FACTORY.to_string()),
685 security_disabled: None,
686 namespace_registration_fee: None,
687 },
688 )
689 }
690
691 fn mock_init_with_account(mut deps: DepsMut, security_disabled: bool) -> VCResult {
693 let admin_info = mock_info(OWNER, &[]);
694 let admin = admin_info.sender.to_string();
695
696 contract::instantiate(
697 deps.branch(),
698 mock_env(),
699 admin_info,
700 InstantiateMsg {
701 admin,
702 security_disabled: Some(security_disabled),
703 namespace_registration_fee: None,
704 },
705 )?;
706 execute_as_admin(
707 deps.branch(),
708 ExecuteMsg::UpdateConfig {
709 account_factory_address: Some(TEST_ACCOUNT_FACTORY.to_string()),
710 security_disabled: None,
711 namespace_registration_fee: None,
712 },
713 )?;
714 execute_as(
715 deps.branch(),
716 TEST_ACCOUNT_FACTORY,
717 ExecuteMsg::AddAccount {
718 account_id: TEST_ACCOUNT_ID,
719 account_base: AccountBase {
720 manager: Addr::unchecked(TEST_MANAGER),
721 proxy: Addr::unchecked(TEST_PROXY),
722 },
723 namespace: None,
724 },
725 )
726 }
727
728 fn create_second_account(deps: DepsMut<'_>) {
729 execute_as(
731 deps,
732 TEST_ACCOUNT_FACTORY,
733 ExecuteMsg::AddAccount {
734 account_id: SECOND_TEST_ACCOUNT_ID,
735 account_base: AccountBase {
736 manager: Addr::unchecked(TEST_MANAGER),
737 proxy: Addr::unchecked(TEST_PROXY),
738 },
739 namespace: None,
740 },
741 )
742 .unwrap();
743 }
744
745 pub const THIRD_ACC_MANAGER: &str = "third-manager";
746 pub const THIRD_ACC_PROXY: &str = "third-proxy";
747 pub const THIRD_ACC_ID: AccountId = AccountId::const_new(3, AccountTrace::Local);
748
749 fn create_third_account(deps: DepsMut<'_>) {
750 execute_as(
752 deps,
753 TEST_ACCOUNT_FACTORY,
754 ExecuteMsg::AddAccount {
755 account_id: SECOND_TEST_ACCOUNT_ID,
756 account_base: AccountBase {
757 manager: Addr::unchecked(THIRD_ACC_MANAGER),
758 proxy: Addr::unchecked(THIRD_ACC_PROXY),
759 },
760 namespace: None,
761 },
762 )
763 .unwrap();
764 }
765
766 fn execute_as(deps: DepsMut, sender: &str, msg: ExecuteMsg) -> VCResult {
767 contract::execute(deps, mock_env(), mock_info(sender, &[]), msg)
768 }
769
770 fn execute_as_with_funds(
771 deps: DepsMut,
772 sender: &str,
773 msg: ExecuteMsg,
774 funds: &[Coin],
775 ) -> VCResult {
776 contract::execute(deps, mock_env(), mock_info(sender, funds), msg)
777 }
778
779 fn execute_as_admin(deps: DepsMut, msg: ExecuteMsg) -> VCResult {
780 execute_as(deps, OWNER, msg)
781 }
782
783 fn test_only_admin(msg: ExecuteMsg) -> VersionControlTestResult {
784 let mut deps = mock_dependencies();
785 mock_init(deps.as_mut())?;
786
787 let _info = mock_info("not_owner", &[]);
788
789 let res = execute_as(deps.as_mut(), "not_owner", msg);
790 assert_that(&res)
791 .is_err()
792 .is_equal_to(VCError::Ownership(OwnershipError::NotOwner {}));
793
794 Ok(())
795 }
796
797 mod set_admin_and_factory {
798 use super::*;
799
800 #[test]
801 fn only_admin_admin() -> VersionControlTestResult {
802 let msg = ExecuteMsg::UpdateOwnership(cw_ownable::Action::TransferOwnership {
803 new_owner: "new_admin".to_string(),
804 expiry: None,
805 });
806
807 test_only_admin(msg)
808 }
809
810 #[test]
811 fn only_admin_factory() -> VersionControlTestResult {
812 let msg = ExecuteMsg::UpdateConfig {
813 account_factory_address: Some("new_factory".to_string()),
814 security_disabled: None,
815 namespace_registration_fee: None,
816 };
817 test_only_admin(msg)
818 }
819
820 #[test]
821 fn updates_admin() -> VersionControlTestResult {
822 let mut deps = mock_dependencies();
823 mock_init(deps.as_mut())?;
824
825 let new_admin = "new_admin";
826 let transfer_msg = ExecuteMsg::UpdateOwnership(cw_ownable::Action::TransferOwnership {
828 new_owner: new_admin.to_string(),
829 expiry: None,
830 });
831
832 let transfer_res = execute_as_admin(deps.as_mut(), transfer_msg).unwrap();
833 assert_eq!(0, transfer_res.messages.len());
834
835 let accept_msg = ExecuteMsg::UpdateOwnership(cw_ownable::Action::AcceptOwnership);
837 let accept_res = execute_as(deps.as_mut(), new_admin, accept_msg).unwrap();
838 assert_eq!(0, accept_res.messages.len());
839
840 assert_that!(cw_ownable::get_ownership(&deps.storage).unwrap().owner)
841 .is_some()
842 .is_equal_to(Addr::unchecked(new_admin));
843
844 Ok(())
845 }
846
847 #[test]
848 fn updates_factory() -> VersionControlTestResult {
849 let mut deps = mock_dependencies();
850 mock_init(deps.as_mut())?;
851
852 let new_factory = "new_factory";
853 let msg = ExecuteMsg::UpdateConfig {
854 account_factory_address: Some(new_factory.to_string()),
855 security_disabled: None,
856 namespace_registration_fee: None,
857 };
858
859 let res = execute_as_admin(deps.as_mut(), msg);
860 assert_that!(&res).is_ok();
861
862 let actual_factory = CONFIG.load(&deps.storage)?.account_factory_address.unwrap();
863
864 assert_that!(&actual_factory).is_equal_to(Addr::unchecked(new_factory));
865 Ok(())
866 }
867 }
868
869 mod claim_namespace {
870 use super::*;
871
872 use abstract_std::AbstractError;
873 use cosmwasm_std::{coins, SubMsg};
874
875 #[test]
876 fn claim_namespaces_by_owner() -> VersionControlTestResult {
877 let mut deps = mock_dependencies();
878 deps.querier = mock_manager_querier().build();
879 mock_init_with_account(deps.as_mut(), true)?;
880 let new_namespace1 = Namespace::new("namespace1").unwrap();
881 let msg = ExecuteMsg::ClaimNamespace {
882 account_id: TEST_ACCOUNT_ID,
883 namespace: new_namespace1.to_string(),
884 };
885 let res = execute_as(deps.as_mut(), OWNER, msg);
886 assert_that!(&res).is_ok();
887
888 create_second_account(deps.as_mut());
889
890 let new_namespace2 = Namespace::new("namespace2").unwrap();
891 let msg = ExecuteMsg::ClaimNamespace {
892 account_id: SECOND_TEST_ACCOUNT_ID,
893 namespace: new_namespace2.to_string(),
894 };
895 let res = execute_as(deps.as_mut(), OWNER, msg);
896 assert_that!(&res).is_ok();
897
898 let account_id = NAMESPACES_INFO.load(&deps.storage, &new_namespace1)?;
899 assert_that!(account_id).is_equal_to(TEST_ACCOUNT_ID);
900 let account_id = NAMESPACES_INFO.load(&deps.storage, &new_namespace2)?;
901 assert_that!(account_id).is_equal_to(SECOND_TEST_ACCOUNT_ID);
902 Ok(())
903 }
904
905 #[test]
906 fn fail_claim_permissioned_namespaces() -> VersionControlTestResult {
907 let mut deps = mock_dependencies();
908 deps.querier = mock_manager_querier().build();
909 mock_init_with_account(deps.as_mut(), false)?;
910 let new_namespace1 = Namespace::new("namespace1").unwrap();
911 let msg = ExecuteMsg::ClaimNamespace {
912 account_id: TEST_ACCOUNT_ID,
913 namespace: new_namespace1.to_string(),
914 };
915 let res = execute_as(deps.as_mut(), OWNER, msg);
917 assert_that!(&res).is_ok();
918
919 let account_id = NAMESPACES_INFO.load(&deps.storage, &new_namespace1)?;
920 assert_that!(account_id).is_equal_to(TEST_ACCOUNT_ID);
921
922 create_third_account(deps.as_mut());
923
924 let new_namespace2 = Namespace::new("namespace2").unwrap();
925
926 let msg = ExecuteMsg::ClaimNamespace {
927 account_id: THIRD_ACC_ID,
928 namespace: new_namespace2.to_string(),
929 };
930
931 let res = execute_as(deps.as_mut(), THIRD_ACC_MANAGER, msg);
932 assert_that!(&res)
933 .is_err()
934 .is_equal_to(VCError::Ownership(OwnershipError::NotOwner));
935
936 Ok(())
937 }
938
939 #[test]
940 fn claim_namespaces_with_fee() -> VersionControlTestResult {
941 let mut deps = mock_dependencies();
942 deps.querier = mock_manager_querier().build();
943
944 mock_init_with_account(deps.as_mut(), true)?;
945
946 let one_namespace_fee = Coin {
947 denom: "ujunox".to_string(),
948 amount: 6u128.into(),
949 };
950
951 execute_as_admin(
952 deps.as_mut(),
953 ExecuteMsg::UpdateConfig {
954 account_factory_address: None,
955 security_disabled: None,
956 namespace_registration_fee: Clearable::new_opt(one_namespace_fee.clone()),
957 },
958 )
959 .unwrap();
960
961 const TEST_ADMIN_PROXY: &str = "test-admin-proxy";
963 execute_as(
964 deps.as_mut(),
965 TEST_ACCOUNT_FACTORY,
966 ExecuteMsg::AddAccount {
967 account_id: ABSTRACT_ACCOUNT_ID,
968 account_base: AccountBase {
969 manager: Addr::unchecked(TEST_MANAGER),
970 proxy: Addr::unchecked(TEST_ADMIN_PROXY),
971 },
972 namespace: None,
973 },
974 )
975 .unwrap();
976
977 let new_namespace1 = Namespace::new("namespace1").unwrap();
978 let msg = ExecuteMsg::ClaimNamespace {
979 account_id: TEST_ACCOUNT_ID,
980 namespace: new_namespace1.to_string(),
981 };
982 let res = execute_as(deps.as_mut(), OWNER, msg.clone());
984 assert_that!(&res)
985 .is_err()
986 .is_equal_to(VCError::Abstract(AbstractError::Fee(format!(
987 "Invalid fee payment sent. Expected {}, sent {:?}",
988 Coin {
989 denom: one_namespace_fee.denom.clone(),
990 amount: one_namespace_fee.amount,
991 },
992 Vec::<Coin>::new()
993 ))));
994
995 let sent_coins = coins(5, "ujunox");
997 let res = execute_as_with_funds(deps.as_mut(), OWNER, msg.clone(), &sent_coins);
998 assert_that!(&res)
999 .is_err()
1000 .is_equal_to(VCError::Abstract(AbstractError::Fee(format!(
1001 "Invalid fee payment sent. Expected {}, sent {:?}",
1002 Coin {
1003 denom: one_namespace_fee.denom.clone(),
1004 amount: one_namespace_fee.amount,
1005 },
1006 sent_coins
1007 ))));
1008
1009 let sent_coins = coins(6, "ujunox");
1011 let res = execute_as_with_funds(deps.as_mut(), OWNER, msg, &sent_coins);
1012 assert_that!(&res)
1013 .is_ok()
1014 .map(|res| &res.messages)
1015 .is_equal_to(vec![SubMsg::new(CosmosMsg::Bank(BankMsg::Send {
1016 to_address: TEST_ADMIN_PROXY.to_string(),
1017 amount: sent_coins,
1018 }))]);
1019
1020 Ok(())
1021 }
1022
1023 #[test]
1024 fn claim_namespaces_not_owner() -> VersionControlTestResult {
1025 let mut deps = mock_dependencies();
1026 deps.querier = mock_manager_querier().build();
1027 mock_init_with_account(deps.as_mut(), true)?;
1028 let new_namespace1 = Namespace::new("namespace1").unwrap();
1029 let msg = ExecuteMsg::ClaimNamespace {
1030 account_id: TEST_ACCOUNT_ID,
1031 namespace: new_namespace1.to_string(),
1032 };
1033 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1034 assert_that!(&res)
1035 .is_err()
1036 .is_equal_to(&VCError::AccountOwnerMismatch {
1037 sender: Addr::unchecked(TEST_OTHER),
1038 owner: Addr::unchecked(OWNER),
1039 });
1040 Ok(())
1041 }
1042
1043 #[test]
1044 fn claim_existing_namespaces() -> VersionControlTestResult {
1045 let mut deps = mock_dependencies();
1046 deps.querier = mock_manager_querier().build();
1047 mock_init_with_account(deps.as_mut(), true)?;
1048 execute_as(
1050 deps.as_mut(),
1051 TEST_ACCOUNT_FACTORY,
1052 ExecuteMsg::AddAccount {
1053 account_id: SECOND_TEST_ACCOUNT_ID,
1054 account_base: AccountBase {
1055 manager: Addr::unchecked(TEST_MANAGER),
1056 proxy: Addr::unchecked(TEST_PROXY),
1057 },
1058 namespace: None,
1059 },
1060 )?;
1061 let new_namespace1 = Namespace::new("namespace1")?;
1062 let msg = ExecuteMsg::ClaimNamespace {
1063 account_id: TEST_ACCOUNT_ID,
1064 namespace: new_namespace1.to_string(),
1065 };
1066 execute_as(deps.as_mut(), OWNER, msg)?;
1067
1068 let msg = ExecuteMsg::ClaimNamespace {
1069 account_id: SECOND_TEST_ACCOUNT_ID,
1070 namespace: new_namespace1.to_string(),
1071 };
1072 let res = execute_as(deps.as_mut(), OWNER, msg);
1073 assert_that!(&res)
1074 .is_err()
1075 .is_equal_to(&VCError::NamespaceOccupied {
1076 namespace: new_namespace1.to_string(),
1077 id: TEST_ACCOUNT_ID,
1078 });
1079 Ok(())
1080 }
1081
1082 #[test]
1083 fn cannot_claim_abstract() -> VCResult<()> {
1084 let mut deps = mock_dependencies();
1085 let account_1_manager = "manager2";
1086 deps.querier = mock_manager_querier()
1087 .with_smart_handler(account_1_manager, |msg| match from_json(msg).unwrap() {
1089 ManagerQueryMsg::Config {} => {
1090 let resp = ManagerConfigResponse {
1091 version_control_address: Addr::unchecked(TEST_VERSION_CONTROL),
1092 module_factory_address: Addr::unchecked(TEST_MODULE_FACTORY),
1093 account_id: TEST_ACCOUNT_ID,
1094 is_suspended: false,
1095 };
1096 Ok(to_json_binary(&resp).unwrap())
1097 }
1098 ManagerQueryMsg::Ownership {} => {
1099 let resp = cw_ownable::Ownership {
1100 owner: Some(Addr::unchecked(OWNER)),
1101 pending_expiry: None,
1102 pending_owner: None,
1103 };
1104 Ok(to_json_binary(&resp).unwrap())
1105 }
1106 _ => panic!("unexpected message"),
1107 })
1108 .with_owner(account_1_manager, Some(OWNER))
1109 .build();
1110 mock_init_with_account(deps.as_mut(), true)?;
1111
1112 execute_as(
1114 deps.as_mut(),
1115 TEST_ACCOUNT_FACTORY,
1116 ExecuteMsg::AddAccount {
1117 account_id: SECOND_TEST_ACCOUNT_ID,
1118 account_base: AccountBase {
1119 manager: Addr::unchecked(account_1_manager),
1120 proxy: Addr::unchecked("proxy2"),
1121 },
1122 namespace: None,
1123 },
1124 )?;
1125
1126 let claim_abstract_msg: ExecuteMsg = ExecuteMsg::ClaimNamespace {
1128 account_id: SECOND_TEST_ACCOUNT_ID,
1129 namespace: ABSTRACT_NAMESPACE.to_string(),
1130 };
1131 let res = execute_as(deps.as_mut(), OWNER, claim_abstract_msg);
1132 assert_that!(&res)
1133 .is_err()
1134 .is_equal_to(VCError::NamespaceOccupied {
1135 namespace: Namespace::try_from("abstract")?.to_string(),
1136 id: ABSTRACT_ACCOUNT_ID,
1137 });
1138 Ok(())
1139 }
1140 }
1141
1142 mod update_direct_registration {
1143 use super::*;
1144
1145 #[test]
1146 fn only_admin() -> VersionControlTestResult {
1147 let mut deps = mock_dependencies();
1148 mock_init(deps.as_mut())?;
1149
1150 let msg = ExecuteMsg::UpdateConfig {
1151 account_factory_address: None,
1152 security_disabled: Some(false),
1153 namespace_registration_fee: None,
1154 };
1155
1156 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1157 assert_that!(&res)
1158 .is_err()
1159 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner));
1160
1161 Ok(())
1162 }
1163
1164 #[test]
1165 fn direct_registration() -> VersionControlTestResult {
1166 let mut deps = mock_dependencies();
1167 mock_init(deps.as_mut())?;
1168
1169 let msg = ExecuteMsg::UpdateConfig {
1170 account_factory_address: None,
1171 security_disabled: Some(false),
1172 namespace_registration_fee: None,
1173 };
1174
1175 let res = execute_as_admin(deps.as_mut(), msg);
1176 assert_that!(&res).is_ok();
1177
1178 assert_that!(CONFIG.load(&deps.storage).unwrap().security_disabled).is_equal_to(false);
1179 assert_that!(CONFIG.load(&deps.storage).unwrap().security_disabled).is_equal_to(false);
1180
1181 Ok(())
1182 }
1183 }
1184
1185 mod update_namespace_fee {
1186 use cosmwasm_std::Uint128;
1187
1188 use super::*;
1189
1190 #[test]
1191 fn only_admin() -> VersionControlTestResult {
1192 let mut deps = mock_dependencies();
1193 mock_init(deps.as_mut())?;
1194
1195 let msg = ExecuteMsg::UpdateConfig {
1196 account_factory_address: None,
1197 security_disabled: None,
1198 namespace_registration_fee: Clearable::new_opt(Coin {
1199 denom: "ujunox".to_string(),
1200 amount: Uint128::one(),
1201 }),
1202 };
1203
1204 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1205 assert_that!(&res)
1206 .is_err()
1207 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner));
1208
1209 Ok(())
1210 }
1211
1212 #[test]
1213 fn updates_fee() -> VersionControlTestResult {
1214 let mut deps = mock_dependencies();
1215 mock_init(deps.as_mut())?;
1216
1217 let new_fee = Coin {
1218 denom: "ujunox".to_string(),
1219 amount: Uint128::one(),
1220 };
1221
1222 let msg = ExecuteMsg::UpdateConfig {
1223 account_factory_address: None,
1224 security_disabled: None,
1225 namespace_registration_fee: Clearable::new_opt(new_fee.clone()),
1226 };
1227
1228 let res = execute_as_admin(deps.as_mut(), msg);
1229 assert_that!(&res).is_ok();
1230
1231 assert_that!(
1232 CONFIG
1233 .load(&deps.storage)
1234 .unwrap()
1235 .namespace_registration_fee
1236 )
1237 .is_equal_to(Some(new_fee));
1238
1239 Ok(())
1240 }
1241 }
1242
1243 mod remove_namespaces {
1244 use super::*;
1245
1246 use cosmwasm_std::attr;
1247
1248 fn test_module() -> ModuleInfo {
1249 ModuleInfo::from_id(TEST_MODULE_ID, ModuleVersion::Version(TEST_VERSION.into()))
1250 .unwrap()
1251 }
1252
1253 #[test]
1254 fn remove_namespaces_by_admin_or_owner() -> VersionControlTestResult {
1255 let mut deps = mock_dependencies();
1256 deps.querier = mock_manager_querier().build();
1257 mock_init_with_account(deps.as_mut(), true)?;
1258 let new_namespace1 = Namespace::new("namespace1").unwrap();
1259 let new_namespace2 = Namespace::new("namespace2").unwrap();
1260
1261 let msg = ExecuteMsg::ClaimNamespace {
1263 account_id: TEST_ACCOUNT_ID,
1264 namespace: new_namespace1.to_string(),
1265 };
1266 execute_as(deps.as_mut(), OWNER, msg)?;
1267
1268 let msg = ExecuteMsg::RemoveNamespaces {
1270 namespaces: vec![new_namespace1.to_string()],
1271 };
1272 let res = execute_as(deps.as_mut(), OWNER, msg);
1273 assert_that!(&res).is_ok();
1274 let exists = NAMESPACES_INFO.has(&deps.storage, &new_namespace1);
1275 assert_that!(exists).is_equal_to(false);
1276
1277 let msg = ExecuteMsg::ClaimNamespace {
1278 account_id: TEST_ACCOUNT_ID,
1279 namespace: new_namespace2.to_string(),
1280 };
1281 execute_as(deps.as_mut(), OWNER, msg)?;
1282
1283 let msg = ExecuteMsg::RemoveNamespaces {
1285 namespaces: vec![new_namespace2.to_string()],
1286 };
1287 let res = execute_as(deps.as_mut(), OWNER, msg);
1288 assert_that!(&res).is_ok();
1289 let exists = NAMESPACES_INFO.has(&deps.storage, &new_namespace2);
1290 assert_that!(exists).is_equal_to(false);
1291 assert_eq!(
1292 res.unwrap().events[0].attributes[2],
1293 attr(
1294 "namespaces",
1295 format!("({}, {})", new_namespace2, TEST_ACCOUNT_ID,),
1296 )
1297 );
1298
1299 Ok(())
1300 }
1301
1302 #[test]
1303 fn remove_namespaces_as_other() -> VersionControlTestResult {
1304 let mut deps = mock_dependencies();
1305 deps.querier = mock_manager_querier().build();
1306 mock_init_with_account(deps.as_mut(), true)?;
1307 let new_namespace1 = Namespace::new("namespace1")?;
1308
1309 let msg = ExecuteMsg::ClaimNamespace {
1311 account_id: TEST_ACCOUNT_ID,
1312 namespace: new_namespace1.to_string(),
1313 };
1314 execute_as(deps.as_mut(), OWNER, msg)?;
1315
1316 let msg = ExecuteMsg::RemoveNamespaces {
1318 namespaces: vec![new_namespace1.to_string()],
1319 };
1320 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1321 assert_that!(&res)
1322 .is_err()
1323 .is_equal_to(&VCError::AccountOwnerMismatch {
1324 sender: Addr::unchecked(TEST_OTHER),
1325 owner: Addr::unchecked(OWNER),
1326 });
1327 Ok(())
1328 }
1329
1330 #[test]
1331 fn remove_not_existing_namespaces() -> VersionControlTestResult {
1332 let mut deps = mock_dependencies();
1333 deps.querier = mock_manager_querier().build();
1334 mock_init_with_account(deps.as_mut(), true)?;
1335 let new_namespace1 = Namespace::new("namespace1")?;
1336
1337 let msg = ExecuteMsg::RemoveNamespaces {
1339 namespaces: vec![new_namespace1.to_string()],
1340 };
1341 let res = execute_as(deps.as_mut(), OWNER, msg.clone());
1342 assert_that!(&res)
1343 .is_err()
1344 .is_equal_to(&VCError::UnknownNamespace {
1345 namespace: new_namespace1.clone(),
1346 });
1347
1348 let res = execute_as(deps.as_mut(), OWNER, msg);
1350 assert_that!(&res)
1351 .is_err()
1352 .is_equal_to(&VCError::UnknownNamespace {
1353 namespace: new_namespace1,
1354 });
1355
1356 Ok(())
1357 }
1358
1359 #[test]
1360 fn yank_orphaned_modules() -> VersionControlTestResult {
1361 let mut deps = mock_dependencies();
1362 deps.querier = mock_manager_querier().build();
1363 mock_init_with_account(deps.as_mut(), true)?;
1364
1365 let new_namespace1 = Namespace::new("namespace1")?;
1367 let msg = ExecuteMsg::ClaimNamespace {
1368 account_id: TEST_ACCOUNT_ID,
1369 namespace: new_namespace1.to_string(),
1370 };
1371 execute_as(deps.as_mut(), OWNER, msg)?;
1372
1373 let mut new_module = test_module();
1375 new_module.namespace = new_namespace1.clone();
1376 let msg = ExecuteMsg::ProposeModules {
1377 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1378 };
1379 execute_as(deps.as_mut(), OWNER, msg)?;
1380
1381 let msg = ExecuteMsg::RemoveNamespaces {
1383 namespaces: vec![new_namespace1.to_string()],
1384 };
1385 execute_as(deps.as_mut(), OWNER, msg)?;
1386
1387 let module = REGISTERED_MODULES.load(&deps.storage, &new_module);
1388 assert_that!(&module).is_err();
1389 let module = YANKED_MODULES.load(&deps.storage, &new_module)?;
1390 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1391 Ok(())
1392 }
1393 }
1394
1395 mod propose_modules {
1396 use super::*;
1397
1398 use crate::contract::query;
1399 use abstract_std::{objects::module::Monetization, AbstractError};
1400 use cosmwasm_std::coin;
1401
1402 fn test_module() -> ModuleInfo {
1403 ModuleInfo::from_id(TEST_MODULE_ID, ModuleVersion::Version(TEST_VERSION.into()))
1404 .unwrap()
1405 }
1406
1407 #[test]
1410 fn add_module_by_admin() -> VersionControlTestResult {
1411 let mut deps = mock_dependencies();
1412 deps.querier = mock_manager_querier().build();
1413 mock_init_with_account(deps.as_mut(), true)?;
1414 let mut new_module = test_module();
1415 new_module.namespace = Namespace::new(ABSTRACT_NAMESPACE)?;
1416 let msg = ExecuteMsg::ProposeModules {
1417 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1418 };
1419 let res = execute_as(deps.as_mut(), OWNER, msg);
1420 assert_that!(&res).is_ok();
1421 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1422 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1423 Ok(())
1424 }
1425
1426 #[test]
1427 fn add_module_by_account_owner() -> VersionControlTestResult {
1428 let mut deps = mock_dependencies();
1429 deps.querier = mock_manager_querier().build();
1430 mock_init_with_account(deps.as_mut(), true)?;
1431 let new_module = test_module();
1432
1433 let msg = ExecuteMsg::ProposeModules {
1434 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1435 };
1436
1437 let res = execute_as(deps.as_mut(), OWNER, msg.clone());
1439 assert_that!(&res)
1440 .is_err()
1441 .is_equal_to(&VCError::UnknownNamespace {
1442 namespace: new_module.namespace.clone(),
1443 });
1444
1445 execute_as(
1447 deps.as_mut(),
1448 OWNER,
1449 ExecuteMsg::ClaimNamespace {
1450 account_id: TEST_ACCOUNT_ID,
1451 namespace: new_module.namespace.to_string(),
1452 },
1453 )?;
1454
1455 let res = execute_as(deps.as_mut(), OWNER, msg);
1457 assert_that!(&res).is_ok();
1458 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1459 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1460 Ok(())
1461 }
1462
1463 #[test]
1464 fn update_existing_module() -> VersionControlTestResult {
1465 let mut deps = mock_dependencies();
1466 deps.querier = mock_manager_querier().build();
1467 mock_init_with_account(deps.as_mut(), true)?;
1468 let new_module = test_module();
1469
1470 let msg = ExecuteMsg::ProposeModules {
1471 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1472 };
1473
1474 execute_as(
1476 deps.as_mut(),
1477 OWNER,
1478 ExecuteMsg::ClaimNamespace {
1479 account_id: TEST_ACCOUNT_ID,
1480 namespace: new_module.namespace.to_string(),
1481 },
1482 )?;
1483
1484 let res = execute_as(deps.as_mut(), OWNER, msg);
1486 assert_that!(&res).is_ok();
1487 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1488 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1489
1490 let msg = ExecuteMsg::ProposeModules {
1493 modules: vec![(new_module.clone(), ModuleReference::App(1))],
1494 };
1495
1496 let res = execute_as(deps.as_mut(), OWNER, msg);
1497 assert_that!(&res).is_ok();
1498 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1499 assert_that!(&module).is_equal_to(&ModuleReference::App(1));
1500 Ok(())
1501 }
1502
1503 #[test]
1504 fn update_existing_module_fails() -> VersionControlTestResult {
1505 let mut deps = mock_dependencies();
1506 deps.querier = mock_manager_querier().build();
1507 mock_init_with_account(deps.as_mut(), false)?;
1508 let new_module = test_module();
1509
1510 let msg = ExecuteMsg::ProposeModules {
1511 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1512 };
1513
1514 execute_as(
1516 deps.as_mut(),
1517 OWNER,
1518 ExecuteMsg::ClaimNamespace {
1519 account_id: TEST_ACCOUNT_ID,
1520 namespace: new_module.namespace.to_string(),
1521 },
1522 )?;
1523
1524 let res = execute_as(deps.as_mut(), OWNER, msg);
1526 assert_that!(&res).is_ok();
1527 let msg = ExecuteMsg::ApproveOrRejectModules {
1529 approves: vec![new_module.clone()],
1530 rejects: vec![],
1531 };
1532
1533 let res = execute_as(deps.as_mut(), OWNER, msg);
1535 assert_that!(&res).is_ok();
1536
1537 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1538 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1539
1540 let msg = ExecuteMsg::ProposeModules {
1543 modules: vec![(new_module.clone(), ModuleReference::App(1))],
1544 };
1545 let res = execute_as(deps.as_mut(), OWNER, msg);
1546 assert_that!(&res).is_err();
1548
1549 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1550 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1551 Ok(())
1552 }
1553
1554 #[test]
1555 fn try_add_module_to_approval_with_admin() -> VersionControlTestResult {
1556 let mut deps = mock_dependencies();
1557 let contract_addr = Addr::unchecked("contract");
1558 deps.querier = mock_manager_querier()
1560 .with_contract_admin(&contract_addr, Addr::unchecked("admin"))
1561 .build();
1562
1563 mock_init_with_account(deps.as_mut(), false)?;
1564 let new_module = test_module();
1565
1566 let mod_ref = ModuleReference::Adapter(contract_addr);
1567
1568 let msg = ExecuteMsg::ProposeModules {
1569 modules: vec![(new_module.clone(), mod_ref)],
1570 };
1571
1572 let res = execute_as(deps.as_mut(), OWNER, msg.clone());
1574 assert_that!(&res)
1575 .is_err()
1576 .is_equal_to(&VCError::UnknownNamespace {
1577 namespace: new_module.namespace.clone(),
1578 });
1579
1580 execute_as(
1582 deps.as_mut(),
1583 OWNER,
1584 ExecuteMsg::ClaimNamespace {
1585 account_id: TEST_ACCOUNT_ID,
1586 namespace: new_module.namespace.to_string(),
1587 },
1588 )?;
1589
1590 let res = execute_as(deps.as_mut(), OWNER, msg);
1592 assert_that!(&res)
1593 .is_err()
1594 .is_equal_to(&VCError::AdminMustBeNone);
1595
1596 Ok(())
1597 }
1598
1599 #[test]
1600 fn add_module_to_approval() -> VersionControlTestResult {
1601 let mut deps = mock_dependencies();
1602 deps.querier = mock_manager_querier().build();
1603 mock_init_with_account(deps.as_mut(), false)?;
1604 let new_module = test_module();
1605
1606 let msg = ExecuteMsg::ProposeModules {
1607 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1608 };
1609
1610 let res = execute_as(deps.as_mut(), OWNER, msg.clone());
1612 assert_that!(&res)
1613 .is_err()
1614 .is_equal_to(&VCError::UnknownNamespace {
1615 namespace: new_module.namespace.clone(),
1616 });
1617
1618 execute_as(
1620 deps.as_mut(),
1621 OWNER,
1622 ExecuteMsg::ClaimNamespace {
1623 account_id: TEST_ACCOUNT_ID,
1624 namespace: new_module.namespace.to_string(),
1625 },
1626 )?;
1627
1628 let res = execute_as(deps.as_mut(), OWNER, msg);
1630 assert_that!(&res).is_ok();
1631 let module = PENDING_MODULES.load(&deps.storage, &new_module)?;
1632 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1633 Ok(())
1634 }
1635
1636 #[test]
1637 fn approve_modules() -> VersionControlTestResult {
1638 let mut deps = mock_dependencies();
1639 deps.querier = mock_manager_querier().build();
1640 mock_init_with_account(deps.as_mut(), false)?;
1641 let new_module = test_module();
1642
1643 execute_as(
1645 deps.as_mut(),
1646 OWNER,
1647 ExecuteMsg::ClaimNamespace {
1648 account_id: TEST_ACCOUNT_ID,
1649 namespace: new_module.namespace.to_string(),
1650 },
1651 )?;
1652 execute_as(
1654 deps.as_mut(),
1655 OWNER,
1656 ExecuteMsg::ProposeModules {
1657 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1658 },
1659 )?;
1660
1661 let msg = ExecuteMsg::ApproveOrRejectModules {
1662 approves: vec![new_module.clone()],
1663 rejects: vec![],
1664 };
1665
1666 let res = execute_as(deps.as_mut(), "not_owner", msg.clone());
1668 assert_that!(&res)
1669 .is_err()
1670 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
1671
1672 let res = execute_as(deps.as_mut(), OWNER, msg);
1674 assert_that!(&res).is_ok();
1675 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1676 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1677 let pending = PENDING_MODULES.has(&deps.storage, &new_module);
1678 assert_that!(pending).is_equal_to(false);
1679
1680 Ok(())
1681 }
1682
1683 #[test]
1684 fn reject_modules() -> VersionControlTestResult {
1685 let mut deps = mock_dependencies();
1686 deps.querier = mock_manager_querier().build();
1687 mock_init_with_account(deps.as_mut(), false)?;
1688 let new_module = test_module();
1689
1690 execute_as(
1692 deps.as_mut(),
1693 OWNER,
1694 ExecuteMsg::ClaimNamespace {
1695 account_id: TEST_ACCOUNT_ID,
1696 namespace: new_module.namespace.to_string(),
1697 },
1698 )?;
1699 execute_as(
1701 deps.as_mut(),
1702 OWNER,
1703 ExecuteMsg::ProposeModules {
1704 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1705 },
1706 )?;
1707
1708 let msg = ExecuteMsg::ApproveOrRejectModules {
1709 approves: vec![],
1710 rejects: vec![new_module.clone()],
1711 };
1712
1713 let res = execute_as(deps.as_mut(), "not_owner", msg.clone());
1715 assert_that!(&res)
1716 .is_err()
1717 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
1718
1719 let res = execute_as(deps.as_mut(), OWNER, msg);
1721 assert_that!(&res).is_ok();
1722 let exists = REGISTERED_MODULES.has(&deps.storage, &new_module);
1723 assert_that!(exists).is_equal_to(false);
1724 let pending = PENDING_MODULES.has(&deps.storage, &new_module);
1725 assert_that!(pending).is_equal_to(false);
1726
1727 Ok(())
1728 }
1729
1730 #[test]
1731 fn remove_module() -> VersionControlTestResult {
1732 let mut deps = mock_dependencies();
1733 deps.querier = mock_manager_querier().build();
1734 mock_init_with_account(deps.as_mut(), true)?;
1735 let rm_module = test_module();
1736
1737 let msg = ExecuteMsg::ClaimNamespace {
1739 account_id: TEST_ACCOUNT_ID,
1740 namespace: rm_module.namespace.to_string(),
1741 };
1742 execute_as(deps.as_mut(), OWNER, msg)?;
1743
1744 let msg = ExecuteMsg::ProposeModules {
1746 modules: vec![(rm_module.clone(), ModuleReference::App(0))],
1747 };
1748 execute_as(deps.as_mut(), OWNER, msg)?;
1749 let module = REGISTERED_MODULES.load(&deps.storage, &rm_module)?;
1750 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1751
1752 let msg = ExecuteMsg::RemoveModule {
1754 module: rm_module.clone(),
1755 };
1756 let res = execute_as(deps.as_mut(), TEST_OTHER, msg.clone());
1758 assert_that!(&res)
1759 .is_err()
1760 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
1761
1762 execute_as_admin(deps.as_mut(), msg)?;
1764
1765 let module = REGISTERED_MODULES.load(&deps.storage, &rm_module);
1766 assert_that!(&module).is_err();
1767 Ok(())
1768 }
1769
1770 #[test]
1771 fn yank_module_only_account_owner() -> VersionControlTestResult {
1772 let mut deps = mock_dependencies();
1773 deps.querier = mock_manager_querier().build();
1774 mock_init_with_account(deps.as_mut(), true)?;
1775 let rm_module = test_module();
1776
1777 let msg = ExecuteMsg::ClaimNamespace {
1779 account_id: TEST_ACCOUNT_ID,
1780 namespace: rm_module.namespace.to_string(),
1781 };
1782 execute_as(deps.as_mut(), OWNER, msg)?;
1783
1784 let add_modules_msg = ExecuteMsg::ProposeModules {
1786 modules: vec![(rm_module.clone(), ModuleReference::App(0))],
1787 };
1788 execute_as(deps.as_mut(), OWNER, add_modules_msg)?;
1789 let added_module = REGISTERED_MODULES.load(&deps.storage, &rm_module)?;
1790 assert_that!(&added_module).is_equal_to(&ModuleReference::App(0));
1791
1792 let msg = ExecuteMsg::YankModule { module: rm_module };
1794 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1796 assert_that!(&res)
1797 .is_err()
1798 .is_equal_to(&VCError::AccountOwnerMismatch {
1799 sender: Addr::unchecked(TEST_OTHER),
1800 owner: Addr::unchecked(OWNER),
1801 });
1802
1803 Ok(())
1804 }
1805
1806 #[test]
1807 fn yank_module() -> VersionControlTestResult {
1808 let mut deps = mock_dependencies();
1809 deps.querier = mock_manager_querier().build();
1810 mock_init_with_account(deps.as_mut(), true)?;
1811 let rm_module = test_module();
1812
1813 let msg = ExecuteMsg::ClaimNamespace {
1815 account_id: TEST_ACCOUNT_ID,
1816 namespace: rm_module.namespace.to_string(),
1817 };
1818 execute_as(deps.as_mut(), OWNER, msg)?;
1819
1820 let add_modules_msg = ExecuteMsg::ProposeModules {
1822 modules: vec![(rm_module.clone(), ModuleReference::App(0))],
1823 };
1824 execute_as(deps.as_mut(), OWNER, add_modules_msg)?;
1825 let added_module = REGISTERED_MODULES.load(&deps.storage, &rm_module)?;
1826 assert_that!(&added_module).is_equal_to(&ModuleReference::App(0));
1827
1828 let msg = ExecuteMsg::YankModule {
1830 module: rm_module.clone(),
1831 };
1832 execute_as(deps.as_mut(), OWNER, msg)?;
1833
1834 let module = REGISTERED_MODULES.load(&deps.storage, &rm_module);
1836 assert_that!(&module).is_err();
1837 let yanked_module = YANKED_MODULES.load(&deps.storage, &rm_module)?;
1838 assert_that!(&yanked_module).is_equal_to(&ModuleReference::App(0));
1839 Ok(())
1840 }
1841
1842 #[test]
1843 fn bad_version() -> VersionControlTestResult {
1844 let mut deps = mock_dependencies();
1845 deps.querier = mock_manager_querier().build();
1846 mock_init_with_account(deps.as_mut(), true)?;
1847
1848 let msg = ExecuteMsg::ClaimNamespace {
1850 account_id: TEST_ACCOUNT_ID,
1851 namespace: "namespace".to_string(),
1852 };
1853 execute_as(deps.as_mut(), OWNER, msg)?;
1854
1855 let bad_version_module = ModuleInfo::from_id(
1856 TEST_MODULE_ID,
1857 ModuleVersion::Version("non_compliant_version".into()),
1858 )?;
1859 let msg = ExecuteMsg::ProposeModules {
1860 modules: vec![(bad_version_module, ModuleReference::App(0))],
1861 };
1862 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1863 assert_that!(&res)
1864 .is_err()
1865 .matches(|e| e.to_string().contains("Invalid version"));
1866
1867 let latest_version_module = ModuleInfo::from_id(TEST_MODULE_ID, ModuleVersion::Latest)?;
1868 let msg = ExecuteMsg::ProposeModules {
1869 modules: vec![(latest_version_module, ModuleReference::App(0))],
1870 };
1871 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1872 assert_that!(&res)
1873 .is_err()
1874 .is_equal_to(&VCError::Abstract(AbstractError::Assert(
1875 "Module version must be set to a specific version".into(),
1876 )));
1877 Ok(())
1878 }
1879
1880 #[test]
1881 fn abstract_namespace() -> VersionControlTestResult {
1882 let mut deps = mock_dependencies();
1883 let abstract_contract_id = format!("{}:{}", ABSTRACT_NAMESPACE, "test-module");
1884 deps.querier = mock_manager_querier().build();
1885 mock_init_with_account(deps.as_mut(), true)?;
1886 let new_module = ModuleInfo::from_id(&abstract_contract_id, TEST_VERSION.into())?;
1887
1888 let msg = ExecuteMsg::ProposeModules {
1890 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1891 };
1892
1893 let res = execute_as(deps.as_mut(), TEST_OTHER, msg.clone());
1895 assert_that!(&res)
1896 .is_err()
1897 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
1898
1899 execute_as_admin(deps.as_mut(), msg)?;
1900 let module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1901 assert_that!(&module).is_equal_to(&ModuleReference::App(0));
1902 Ok(())
1903 }
1904
1905 #[test]
1906 fn validates_module_info() -> VersionControlTestResult {
1907 let mut deps = mock_dependencies();
1908 deps.querier = mock_manager_querier().build();
1909 mock_init_with_account(deps.as_mut(), true)?;
1910 let bad_modules = vec![
1911 ModuleInfo {
1912 name: "test-module".to_string(),
1913 version: ModuleVersion::Version("0.0.1".to_string()),
1914 namespace: Namespace::unchecked(""),
1915 },
1916 ModuleInfo {
1917 name: "test-module".to_string(),
1918 version: ModuleVersion::Version("0.0.1".to_string()),
1919 namespace: Namespace::unchecked(""),
1920 },
1921 ModuleInfo {
1922 name: "".to_string(),
1923 version: ModuleVersion::Version("0.0.1".to_string()),
1924 namespace: Namespace::unchecked("test"),
1925 },
1926 ModuleInfo {
1927 name: "test-module".to_string(),
1928 version: ModuleVersion::Version("aoeu".to_string()),
1929 namespace: Namespace::unchecked(""),
1930 },
1931 ];
1932
1933 for bad_module in bad_modules {
1934 let msg = ExecuteMsg::ProposeModules {
1935 modules: vec![(bad_module.clone(), ModuleReference::App(0))],
1936 };
1937 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
1938 assert_that!(&res)
1939 .named(&format!("ModuleInfo validation failed for {bad_module}"))
1940 .is_err()
1941 .is_equal_to(&VCError::Abstract(AbstractError::FormattingError {
1942 object: "module name".into(),
1943 expected: "with content".into(),
1944 actual: "empty".into(),
1945 }));
1946 }
1947
1948 Ok(())
1949 }
1950
1951 #[test]
1952 fn add_module_monetization() -> VersionControlTestResult {
1953 let mut deps = mock_dependencies();
1954 deps.querier = mock_manager_querier().build();
1955 mock_init_with_account(deps.as_mut(), true)?;
1956 let mut new_module = test_module();
1957 new_module.namespace = Namespace::new(ABSTRACT_NAMESPACE)?;
1958 let msg = ExecuteMsg::ProposeModules {
1959 modules: vec![(new_module.clone(), ModuleReference::App(0))],
1960 };
1961 let res = execute_as(deps.as_mut(), OWNER, msg);
1962 assert_that!(&res).is_ok();
1963 let _module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
1964
1965 let monetization = Monetization::InstallFee(FixedFee::new(&coin(45, "ujuno")));
1966 let metadata = None;
1967 let monetization_module_msg = ExecuteMsg::UpdateModuleConfiguration {
1968 module_name: new_module.name.clone(),
1969 namespace: new_module.namespace.clone(),
1970 update_module: UpdateModule::Versioned {
1971 version: TEST_VERSION.to_owned(),
1972 metadata: None,
1973 monetization: Some(monetization.clone()),
1974 instantiation_funds: None,
1975 },
1976 };
1977 execute_as(deps.as_mut(), OWNER, monetization_module_msg)?;
1978
1979 let query_msg = QueryMsg::Modules {
1981 infos: vec![new_module.clone()],
1982 };
1983 let res = query(deps.as_ref(), mock_env(), query_msg)?;
1984 let ser_res = from_json::<ModulesResponse>(&res)?;
1985 assert_that!(ser_res.modules).has_length(1);
1986 assert_eq!(
1987 ser_res.modules[0],
1988 ModuleResponse {
1989 module: Module {
1990 info: new_module,
1991 reference: ModuleReference::App(0)
1992 },
1993 config: ModuleConfiguration::new(monetization, metadata, vec![])
1994 }
1995 );
1996
1997 Ok(())
1998 }
1999
2000 #[test]
2001 fn add_module_init_funds() -> VersionControlTestResult {
2002 let mut deps = mock_dependencies();
2003 deps.querier = mock_manager_querier().build();
2004 mock_init_with_account(deps.as_mut(), true)?;
2005 let mut new_module = test_module();
2006 new_module.namespace = Namespace::new(ABSTRACT_NAMESPACE)?;
2007 let msg = ExecuteMsg::ProposeModules {
2008 modules: vec![(new_module.clone(), ModuleReference::App(0))],
2009 };
2010 let res = execute_as(deps.as_mut(), OWNER, msg);
2011 assert_that!(&res).is_ok();
2012 let _module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
2013
2014 let instantiation_funds = vec![coin(42, "ujuno"), coin(123, "ujunox")];
2015 let metadata = None;
2016 let monetization_module_msg = ExecuteMsg::UpdateModuleConfiguration {
2017 module_name: new_module.name.clone(),
2018 namespace: new_module.namespace.clone(),
2019 update_module: UpdateModule::Versioned {
2020 version: TEST_VERSION.to_owned(),
2021 metadata: None,
2022 monetization: None,
2023 instantiation_funds: Some(instantiation_funds.clone()),
2024 },
2025 };
2026 execute_as(deps.as_mut(), OWNER, monetization_module_msg)?;
2027
2028 let query_msg = QueryMsg::Modules {
2030 infos: vec![new_module.clone()],
2031 };
2032 let res = query(deps.as_ref(), mock_env(), query_msg)?;
2033 let ser_res = from_json::<ModulesResponse>(&res)?;
2034 assert_that!(ser_res.modules).has_length(1);
2035 assert_eq!(
2036 ser_res.modules[0],
2037 ModuleResponse {
2038 module: Module {
2039 info: new_module,
2040 reference: ModuleReference::App(0)
2041 },
2042 config: ModuleConfiguration::new(
2043 Monetization::None,
2044 metadata,
2045 instantiation_funds
2046 )
2047 }
2048 );
2049
2050 Ok(())
2051 }
2052
2053 #[test]
2054 fn add_module_metadata() -> VersionControlTestResult {
2055 let mut deps = mock_dependencies();
2056 deps.querier = mock_manager_querier().build();
2057 mock_init_with_account(deps.as_mut(), true)?;
2058 let mut new_module = test_module();
2059 new_module.namespace = Namespace::new(ABSTRACT_NAMESPACE)?;
2060 let msg = ExecuteMsg::ProposeModules {
2061 modules: vec![(new_module.clone(), ModuleReference::App(0))],
2062 };
2063 let res = execute_as(deps.as_mut(), OWNER, msg);
2064 assert_that!(&res).is_ok();
2065 let _module = REGISTERED_MODULES.load(&deps.storage, &new_module)?;
2066
2067 let monetization = Monetization::None;
2068 let metadata = Some("ipfs://YRUI243876FJHKHV3IY".to_string());
2069 let metadata_module_msg = ExecuteMsg::UpdateModuleConfiguration {
2070 module_name: new_module.name.clone(),
2071 namespace: new_module.namespace.clone(),
2072 update_module: UpdateModule::Versioned {
2073 version: TEST_VERSION.to_owned(),
2074 metadata: metadata.clone(),
2075 monetization: None,
2076 instantiation_funds: None,
2077 },
2078 };
2079 execute_as(deps.as_mut(), OWNER, metadata_module_msg)?;
2080
2081 let query_msg = QueryMsg::Modules {
2083 infos: vec![new_module.clone()],
2084 };
2085 let res = query(deps.as_ref(), mock_env(), query_msg)?;
2086 let ser_res = from_json::<ModulesResponse>(&res)?;
2087 assert_that!(ser_res.modules).has_length(1);
2088 assert_eq!(
2089 ser_res.modules[0],
2090 ModuleResponse {
2091 module: Module {
2092 info: new_module,
2093 reference: ModuleReference::App(0)
2094 },
2095 config: ModuleConfiguration::new(monetization, metadata, vec![])
2096 }
2097 );
2098
2099 Ok(())
2100 }
2101 }
2102
2103 fn claim_test_namespace_as_owner(deps: DepsMut) -> VersionControlTestResult {
2104 let msg = ExecuteMsg::ClaimNamespace {
2105 account_id: TEST_ACCOUNT_ID,
2106 namespace: TEST_NAMESPACE.to_string(),
2107 };
2108 execute_as(deps, OWNER, msg)?;
2109 Ok(())
2110 }
2111
2112 mod remove_module {
2113 use super::*;
2114
2115 #[test]
2116 fn test_only_admin() -> VersionControlTestResult {
2117 let mut deps = mock_dependencies();
2118 deps.querier = mock_manager_querier().build();
2119 mock_init_with_account(deps.as_mut(), true)?;
2120 claim_test_namespace_as_owner(deps.as_mut())?;
2121
2122 let mut new_module = ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?;
2124 new_module.namespace = Namespace::new(TEST_NAMESPACE)?;
2125 let msg = ExecuteMsg::ProposeModules {
2126 modules: vec![(new_module.clone(), ModuleReference::App(0))],
2127 };
2128 execute_as(deps.as_mut(), OWNER, msg)?;
2129
2130 assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_true();
2132
2133 let msg = ExecuteMsg::RemoveModule { module: new_module };
2135 let res = execute_as(deps.as_mut(), TEST_OTHER, msg);
2136
2137 assert_that!(res)
2138 .is_err()
2139 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
2140 Ok(())
2141 }
2142
2143 #[test]
2144 fn remove_from_library() -> VersionControlTestResult {
2145 let mut deps = mock_dependencies();
2146 deps.querier = mock_manager_querier().build();
2147 mock_init_with_account(deps.as_mut(), true)?;
2148 claim_test_namespace_as_owner(deps.as_mut())?;
2149
2150 let new_module = ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?;
2152 let msg = ExecuteMsg::ProposeModules {
2153 modules: vec![(new_module.clone(), ModuleReference::App(0))],
2154 };
2155 execute_as(deps.as_mut(), OWNER, msg)?;
2156
2157 assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_true();
2159
2160 let msg = ExecuteMsg::RemoveModule {
2162 module: new_module.clone(),
2163 };
2164 execute_as_admin(deps.as_mut(), msg)?;
2165
2166 assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_false();
2167 Ok(())
2168 }
2169
2170 #[test]
2171 fn leaves_pending() -> VersionControlTestResult {
2172 let mut deps = mock_dependencies();
2173 deps.querier = mock_manager_querier().build();
2174 mock_init_with_account(deps.as_mut(), true)?;
2175 claim_test_namespace_as_owner(deps.as_mut())?;
2176
2177 let new_module = ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?;
2179 PENDING_MODULES.save(deps.as_mut().storage, &new_module, &ModuleReference::App(0))?;
2180
2181 let msg = ExecuteMsg::RemoveModule {
2183 module: new_module.clone(),
2184 };
2185 let res = execute_as_admin(deps.as_mut(), msg);
2186
2187 assert_that!(res)
2188 .is_err()
2189 .is_equal_to(&VCError::ModuleNotFound(new_module));
2190 Ok(())
2191 }
2192
2193 #[test]
2194 fn remove_from_yanked() -> VersionControlTestResult {
2195 let mut deps = mock_dependencies();
2196 deps.querier = mock_manager_querier().build();
2197 mock_init_with_account(deps.as_mut(), true)?;
2198 claim_test_namespace_as_owner(deps.as_mut())?;
2199
2200 let new_module = ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?;
2202 YANKED_MODULES.save(deps.as_mut().storage, &new_module, &ModuleReference::App(0))?;
2203
2204 assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_false();
2206 assert_that!(YANKED_MODULES.has(&deps.storage, &new_module)).is_true();
2207
2208 let msg = ExecuteMsg::RemoveModule {
2210 module: new_module.clone(),
2211 };
2212 execute_as_admin(deps.as_mut(), msg)?;
2213
2214 assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_false();
2215 assert_that!(YANKED_MODULES.has(&deps.storage, &new_module)).is_false();
2216 Ok(())
2217 }
2218 }
2219
2220 mod register_os {
2221 use super::*;
2222
2223 #[test]
2224 fn add_os() -> VersionControlTestResult {
2225 let mut deps = mock_dependencies();
2226 mock_init_with_factory(deps.as_mut())?;
2227
2228 let test_core: AccountBase = AccountBase {
2229 manager: Addr::unchecked(TEST_MANAGER),
2230 proxy: Addr::unchecked(TEST_PROXY),
2231 };
2232 let msg = ExecuteMsg::AddAccount {
2233 account_id: ABSTRACT_ACCOUNT_ID,
2234 account_base: test_core.clone(),
2235 namespace: None,
2236 };
2237
2238 let res = execute_as(deps.as_mut(), TEST_OTHER, msg.clone());
2240 assert_that!(&res)
2241 .is_err()
2242 .is_equal_to(&VCError::NotAccountFactory {});
2243
2244 let res = execute_as_admin(deps.as_mut(), msg.clone());
2246 assert_that!(&res)
2247 .is_err()
2248 .is_equal_to(&VCError::NotAccountFactory {});
2249
2250 execute_as(deps.as_mut(), TEST_ACCOUNT_FACTORY, msg)?;
2252
2253 let account = ACCOUNT_ADDRESSES.load(&deps.storage, &ABSTRACT_ACCOUNT_ID)?;
2254 assert_that!(&account).is_equal_to(&test_core);
2255 Ok(())
2256 }
2257 }
2258
2259 mod configure {
2260 use super::*;
2261
2262 #[test]
2263 fn update_admin() -> VersionControlTestResult {
2264 let mut deps = mock_dependencies();
2265 mock_init(deps.as_mut())?;
2266
2267 let transfer_msg = ExecuteMsg::UpdateOwnership(cw_ownable::Action::TransferOwnership {
2268 new_owner: TEST_OTHER.to_string(),
2269 expiry: None,
2270 });
2271
2272 let transfer_res = execute_as(deps.as_mut(), TEST_OTHER, transfer_msg.clone());
2274 assert_that!(&transfer_res)
2275 .is_err()
2276 .is_equal_to(&VCError::Ownership(OwnershipError::NotOwner {}));
2277
2278 execute_as_admin(deps.as_mut(), transfer_msg)?;
2279
2280 let accept_msg = ExecuteMsg::UpdateOwnership(cw_ownable::Action::AcceptOwnership);
2282 let accept_res = execute_as(deps.as_mut(), TEST_OTHER, accept_msg).unwrap();
2283 assert_eq!(0, accept_res.messages.len());
2284
2285 assert_that!(cw_ownable::get_ownership(&deps.storage).unwrap().owner)
2286 .is_some()
2287 .is_equal_to(Addr::unchecked(TEST_OTHER));
2288 Ok(())
2289 }
2290
2291 #[test]
2292 fn set_factory() -> VersionControlTestResult {
2293 let mut deps = mock_dependencies();
2294 mock_init(deps.as_mut())?;
2295
2296 let msg = ExecuteMsg::UpdateConfig {
2297 account_factory_address: Some(TEST_ACCOUNT_FACTORY.into()),
2298 security_disabled: None,
2299 namespace_registration_fee: None,
2300 };
2301
2302 test_only_admin(msg.clone())?;
2303
2304 execute_as_admin(deps.as_mut(), msg)?;
2305 let new_factory = CONFIG.load(&deps.storage)?.account_factory_address;
2306 assert_that!(new_factory).is_equal_to(&Some(Addr::unchecked(TEST_ACCOUNT_FACTORY)));
2307 Ok(())
2308 }
2309 }
2310
2311 mod query_account_owner {
2312 use abstract_sdk::namespaces::OWNERSHIP_STORAGE_KEY;
2313
2314 use super::*;
2315
2316 #[test]
2317 fn returns_account_owner() -> VersionControlTestResult {
2318 let mut deps = mock_dependencies();
2319 deps.querier = AbstractMockQuerierBuilder::default()
2320 .account(TEST_MANAGER, TEST_PROXY, ABSTRACT_ACCOUNT_ID)
2321 .build();
2322 mock_init_with_account(deps.as_mut(), true)?;
2323
2324 let account_owner = query_account_owner(
2325 &deps.as_ref().querier,
2326 Addr::unchecked(TEST_MANAGER),
2327 &ABSTRACT_ACCOUNT_ID,
2328 )?;
2329
2330 assert_that!(account_owner).is_equal_to(Addr::unchecked(OWNER));
2331 Ok(())
2332 }
2333
2334 #[test]
2335 fn no_owner_returns_err() -> VersionControlTestResult {
2336 let mut deps = mock_dependencies();
2337 deps.querier = MockQuerierBuilder::default()
2338 .with_contract_item(
2339 TEST_MANAGER,
2340 cw_storage_plus::Item::<ownership::Ownership<Addr>>::new(OWNERSHIP_STORAGE_KEY),
2341 &ownership::Ownership {
2342 owner: ownership::GovernanceDetails::Renounced {},
2343 pending_owner: None,
2344 pending_expiry: None,
2345 },
2346 )
2347 .build();
2348 mock_init_with_account(deps.as_mut(), true)?;
2349
2350 let account_id = ABSTRACT_ACCOUNT_ID;
2351 let res = query_account_owner(
2352 &deps.as_ref().querier,
2353 Addr::unchecked(TEST_MANAGER),
2354 &account_id,
2355 );
2356 assert_that!(res)
2357 .is_err()
2358 .is_equal_to(&VCError::NoAccountOwner { account_id });
2359 Ok(())
2360 }
2361 }
2362}