abstract_client/
application.rs

1//! # Represents Abstract Application
2//!
3//! [`Application`] represents a module installed on a (sub-)account
4
5use abstract_interface::{AccountExecFns, RegisteredModule};
6use abstract_std::objects::module::ModuleInfo;
7use cosmwasm_std::to_json_binary;
8use cw_orch::{contract::Contract, prelude::*};
9
10use crate::{account::Account, client::AbstractClientResult, Service};
11
12/// An application represents a module installed on a (sub)-[`Account`].
13///
14/// It implements cw-orch traits of the module itself, so you can call its methods directly from the application struct.
15#[derive(Clone)]
16pub struct Application<T: CwEnv, M> {
17    pub(crate) account: Account<T>,
18    pub(crate) module: M,
19}
20
21/// Allows to access the module's methods directly from the application struct
22impl<Chain: CwEnv, M: InstantiableContract + ContractInstance<Chain>> InstantiableContract
23    for Application<Chain, M>
24{
25    type InstantiateMsg = M::InstantiateMsg;
26}
27
28impl<Chain: CwEnv, M: QueryableContract + ContractInstance<Chain>> QueryableContract
29    for Application<Chain, M>
30{
31    type QueryMsg = M::QueryMsg;
32}
33
34impl<Chain: CwEnv, M: ExecutableContract + ContractInstance<Chain>> ExecutableContract
35    for Application<Chain, M>
36{
37    type ExecuteMsg = M::ExecuteMsg;
38}
39
40impl<Chain: CwEnv, M: MigratableContract + ContractInstance<Chain>> MigratableContract
41    for Application<Chain, M>
42{
43    type MigrateMsg = M::MigrateMsg;
44}
45
46impl<Chain: CwEnv, M: ContractInstance<Chain>> ContractInstance<Chain> for Application<Chain, M> {
47    fn as_instance(&self) -> &Contract<Chain> {
48        self.module.as_instance()
49    }
50
51    fn as_instance_mut(&mut self) -> &mut Contract<Chain> {
52        self.module.as_instance_mut()
53    }
54}
55
56impl<Chain: CwEnv, M: RegisteredModule> Application<Chain, M> {
57    /// Get module interface installed on provided account
58    pub(crate) fn new(account: Account<Chain>, module: M) -> AbstractClientResult<Self> {
59        // Sanity check: the module must be installed on the account
60        account.module_addresses(vec![M::module_id().to_string()])?;
61        Ok(Self { account, module })
62    }
63
64    /// Sub-account on which application is installed
65    pub fn account(&self) -> &Account<Chain> {
66        &self.account
67    }
68
69    /// Attempts to get a module on the application. This would typically be a dependency of the
70    /// module of type `M`.
71    pub fn module<T: RegisteredModule + From<Contract<Chain>>>(&self) -> AbstractClientResult<T> {
72        self.account.module()
73    }
74
75    /// Turn the `Application` into a [`Service`] for registration in ANS.
76    pub fn into_service(self) -> Service<Chain, M> {
77        Service::from(self)
78    }
79}
80
81impl<Chain: CwEnv, M: RegisteredModule + MigratableContract> Application<Chain, M> {
82    /// Upgrade module on account to version of `Application`
83    pub fn upgrade(&self, migrate_msg: Option<&M::MigrateMsg>) -> AbstractClientResult<()> {
84        let module = ModuleInfo::from_id(M::module_id(), M::module_version().into())?;
85        if !self.account.module_version_installed(module.clone())? {
86            self.account.abstr_account.upgrade(vec![(
87                module,
88                migrate_msg.map(|msg| to_json_binary(msg).unwrap()),
89            )])?;
90        }
91        Ok(())
92    }
93}
94
95impl<Chain: CwEnv, M: ContractInstance<Chain>> Application<Chain, M> {
96    /// Authorize this application on installed adapters. Accepts Module Id's of adapters
97    pub fn authorize_on_adapters(&self, adapter_ids: &[&str]) -> AbstractClientResult<()> {
98        for module_id in adapter_ids {
99            self.account
100                .abstr_account
101                .update_adapter_authorized_addresses(module_id, vec![self.addr_str()?], vec![])?;
102        }
103        Ok(())
104    }
105}