abstract_version_control/
commands.rs

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
33/// Add new Account to version control contract
34/// Only Factory can add Account
35pub 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    // Only Factory can add new Account
45    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    // Check if account already exists
54    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
89/// Here we can add logic to allow subscribers to claim a namespace and upload contracts to that namespace
90pub 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        // version must be set in order to add the new version
110        module.assert_version_variant()?;
111
112        if module.namespace == Namespace::unchecked(ABSTRACT_NAMESPACE) {
113            // Only Admin can update abstract contracts
114            cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
115        } else {
116            // Only owner can add modules
117            validate_account_owner(deps.as_ref(), &module.namespace, &msg_info.sender)?;
118        }
119
120        // verify contract admin is None if module is Adapter
121        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            // assert that its data is equal to what it wants to be registered under.
129            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            // Save module info of standalone contracts,
139            // helps querying version for cw-2-less or mis-formatted contracts
140            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
151/// Approve and reject modules
152pub fn approve_or_reject_modules(
153    deps: DepsMut,
154    msg_info: MessageInfo,
155    approves: Vec<ModuleInfo>,
156    rejects: Vec<ModuleInfo>,
157) -> VCResult {
158    // Only Admin can approve or rejects a module
159    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
175/// Admin approve modules
176fn 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        // Register the module
182        REGISTERED_MODULES.save(storage, module, &mod_ref)?;
183        // Remove from pending
184        PENDING_MODULES.remove(storage, module);
185
186        // Save module info of standalone contracts,
187        // helps querying version for cw-2-less or mis-formatted contracts
188        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
197/// Admin reject modules
198fn 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
210/// Remove a module from the Version Control registry.
211pub fn remove_module(deps: DepsMut, msg_info: MessageInfo, module: ModuleInfo) -> VCResult {
212    // Only the Version Control Admin can remove modules
213    cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
214
215    // Only specific versions may be removed
216    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    // Remove standalone info
230    if let Ok(ModuleReference::Standalone(id)) = module_ref_res {
231        STANDALONE_INFOS.remove(deps.storage, id);
232    }
233
234    // If this module has no more versions, we also remove default configuration
235    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
249/// Yank a module, preventing it from being used.
250pub fn yank_module(deps: DepsMut, msg_info: MessageInfo, module: ModuleInfo) -> VCResult {
251    // validate the caller is the owner of the namespace
252    validate_account_owner(deps.as_ref(), &module.namespace, &msg_info.sender)?;
253
254    // Only specific versions may be yanked
255    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
269/// Updates module configuration
270pub 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    // validate the caller is the owner of the namespace
278
279    if namespace == Namespace::unchecked(ABSTRACT_NAMESPACE) {
280        // Only Admin can update abstract contracts
281        cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
282    } else {
283        // Only owner can add modules
284        validate_account_owner(deps.as_ref(), &namespace, &msg_info.sender)?;
285    }
286
287    match update_module {
288        UpdateModule::Default { metadata } => {
289            // Check there is at least one version of this module
290            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            // We verify the module exists before updating the config
324            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            // Update metadata
332            if let Some(metadata) = metadata {
333                current_cfg.metadata = Some(metadata);
334            }
335
336            // Update monetization
337            if let Some(monetization) = monetization {
338                current_cfg.monetization = monetization;
339            }
340
341            // Update init funds
342            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, &current_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
366/// Claim namespaces
367/// Only the Account Owner can do this
368pub 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        // When security is enabled, only the contract admin can claim namespaces
382        cw_ownable::assert_owner(deps.storage, &msg_info.sender)?;
383    } else {
384        // If there is no security, only account owner can register a namespace
385        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        // The account owner as well as the account factory contract are able to claim namespaces
389        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
419/// Claim namespace internal
420fn 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    // check if the account already has a namespace
428    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        // assert it is paid
445        FixedFee::new(&fee).assert_payment(&msg_info)?;
446
447        // We transfer the namespace fee if necessary
448        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
469/// Remove namespaces
470/// Only admin or the account owner can do this
471pub 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    // Check manager first, manager can call this function to unregister a namespace when renouncing its ownership.
601    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, // mock value, not used
646                            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    /// Initialize the version_control with admin and updated account_factory
667    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    /// Initialize the version_control with admin as creator and test account
692    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        // create second account
730        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        // create second account
751        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            // First update to transfer
827            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            // Then update and accept as the new owner
836            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            // OWNER is also admin of the contract so this succeeds
916            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            // We create a 0 admin account
962            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            // Fail, no fee at all
983            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            // Fail, not enough fee
996            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            // Success
1010            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            // create second account
1049            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                // add manager 2
1088                .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            // Add account 1
1113            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            // Attempt to claim the abstract namespace with account 1
1127            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            // add namespaces
1262            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            // remove as admin
1269            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            // remove as owner
1284            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            // add namespaces
1310            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            // remove as other
1317            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            // remove as owner
1338            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            // remove as admin
1349            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            // add namespaces
1366            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            // first add module
1374            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            // remove as admin
1382            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        // - Query latest
1408
1409        #[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            // try while no namespace
1438            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            // add namespaces
1446            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            // add modules
1456            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            // add namespaces
1475            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            // add modules
1485            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            // update module code-id without changing version
1491
1492            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            // add namespaces
1515            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            // add modules
1525            let res = execute_as(deps.as_mut(), OWNER, msg);
1526            assert_that!(&res).is_ok();
1527            // approve
1528            let msg = ExecuteMsg::ApproveOrRejectModules {
1529                approves: vec![new_module.clone()],
1530                rejects: vec![],
1531            };
1532
1533            // approve by admin
1534            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            // try update module code-id without changing version
1541
1542            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            // should error as module is already approved and registered.
1547            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            // create mock with ContractInfo response for contract with admin set
1559            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            // try while no namespace
1573            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            // add namespaces
1581            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            // assert we got admin must be none error
1591            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            // try while no namespace
1611            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            // add namespaces
1619            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            // add modules
1629            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            // add namespaces
1644            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            // add modules
1653            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            // approve by not owner
1667            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            // approve by admin
1673            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            // add namespaces
1691            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            // add modules
1700            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            // reject by not owner
1714            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            // reject by admin
1720            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            // add namespaces
1738            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            // first add module
1745            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            // then remove
1753            let msg = ExecuteMsg::RemoveModule {
1754                module: rm_module.clone(),
1755            };
1756            // as other, should fail
1757            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            // only admin can remove modules.
1763            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            // add namespaces as the account owner
1778            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            // first add module as the account owner
1785            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            // then yank the module as the other
1793            let msg = ExecuteMsg::YankModule { module: rm_module };
1794            // as other
1795            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            // add namespaces as the owner
1814            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            // first add module as the owner
1821            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            // then yank as owner
1829            let msg = ExecuteMsg::YankModule {
1830                module: rm_module.clone(),
1831            };
1832            execute_as(deps.as_mut(), OWNER, msg)?;
1833
1834            // check that the yanked module is in the yanked modules and no longer in the library
1835            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            // add namespaces
1849            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 mod_ref = ModuleReference::
1889            let msg = ExecuteMsg::ProposeModules {
1890                modules: vec![(new_module.clone(), ModuleReference::App(0))],
1891            };
1892
1893            // execute as other
1894            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            // We query the module to see if the monetization is attached ok
1980            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            // We query the module to see if the monetization is attached ok
2029            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            // We query the module to see if the monetization is attached ok
2082            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            // add a module as the owner
2123            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            // Load the module from the library to check its presence
2131            assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_true();
2132
2133            // now, remove the module as the admin
2134            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            // add a module as the owner
2151            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            // Load the module from the library to check its presence
2158            assert_that!(REGISTERED_MODULES.has(&deps.storage, &new_module)).is_true();
2159
2160            // now, remove the module as the admin
2161            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            // add a module as the owner
2178            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            // yank the module as the owner
2182            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            // add a module as the owner
2201            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            // should be removed from library and added to yanked
2205            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            // now, remove the module as the admin
2209            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            // as other
2239            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            // as admin
2245            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            // as factory
2251            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            // as other
2273            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            // Then update and accept as the new owner
2281            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}