abstract_core/core/
manager.rs

1//! # Account Manager
2//!
3//! `abstract_core::manager` implements the contract interface and state lay-out.
4//!
5//! ## Description
6//!
7//! The Account manager is part of the Core Abstract Account contracts along with the `abstract_core::proxy` contract.
8//! This contract is responsible for:
9//! - Managing modules instantiation and migrations.
10//! - Managing permissions.
11//! - Upgrading the Account and its modules.
12//! - Providing module name to address resolution.
13//!
14//! **The manager should be set as the contract/CosmWasm admin by default on your modules.**
15//! ## Migration
16//! Migrating this contract is done by calling `ExecuteMsg::Upgrade` with `abstract::manager` as module.
17pub mod state {
18    use std::collections::HashSet;
19
20    use cosmwasm_std::{Addr, Deps};
21    use cw_address_like::AddressLike;
22    use cw_ownable::Ownership;
23    use cw_storage_plus::{Item, Map};
24
25    pub use crate::objects::account::ACCOUNT_ID;
26    use crate::objects::{
27        common_namespace::OWNERSHIP_STORAGE_KEY, gov_type::GovernanceDetails, module::ModuleId,
28    };
29
30    pub type SuspensionStatus = bool;
31
32    /// Manager configuration
33    #[cosmwasm_schema::cw_serde]
34    pub struct Config {
35        pub version_control_address: Addr,
36        pub module_factory_address: Addr,
37    }
38
39    /// Abstract Account details.
40    #[cosmwasm_schema::cw_serde]
41    pub struct AccountInfo<T: AddressLike = Addr> {
42        pub name: String,
43        pub governance_details: GovernanceDetails<T>,
44        pub chain_id: String,
45        pub description: Option<String>,
46        pub link: Option<String>,
47    }
48
49    impl AccountInfo<String> {
50        /// Check an account's info, verifying the gov details.
51        pub fn verify(
52            self,
53            deps: Deps,
54            version_control_addr: Addr,
55        ) -> Result<AccountInfo<Addr>, crate::AbstractError> {
56            let governance_details = self.governance_details.verify(deps, version_control_addr)?;
57            Ok(AccountInfo {
58                name: self.name,
59                governance_details,
60                chain_id: self.chain_id,
61                description: self.description,
62                link: self.link,
63            })
64        }
65    }
66
67    impl From<AccountInfo<Addr>> for AccountInfo<String> {
68        fn from(value: AccountInfo<Addr>) -> Self {
69            AccountInfo {
70                name: value.name,
71                governance_details: value.governance_details.into(),
72                chain_id: value.chain_id,
73                description: value.description,
74                link: value.link,
75            }
76        }
77    }
78
79    /// Suspension status
80    pub const SUSPENSION_STATUS: Item<SuspensionStatus> = Item::new("\u{0}{12}is_suspended");
81    /// Configuration
82    pub const CONFIG: Item<Config> = Item::new("\u{0}{6}config");
83    /// Info about the Account
84    pub const INFO: Item<AccountInfo<Addr>> = Item::new("\u{0}{4}info");
85    /// Account owner - managed by cw-ownable
86    pub const OWNER: Item<Ownership<Addr>> = Item::new(OWNERSHIP_STORAGE_KEY);
87    /// Enabled Abstract modules
88    pub const ACCOUNT_MODULES: Map<ModuleId, Addr> = Map::new("modules");
89    /// Stores the dependency relationship between modules
90    /// map module -> modules that depend on module.
91    pub const DEPENDENTS: Map<ModuleId, HashSet<String>> = Map::new("dependents");
92    /// List of sub-accounts
93    pub const SUB_ACCOUNTS: Map<u32, cosmwasm_std::Empty> = Map::new("sub_accs");
94    /// Pending new governance
95    pub const PENDING_GOVERNANCE: Item<GovernanceDetails<Addr>> = Item::new("pgov");
96    /// Context for old adapters that are currently removing authorized addresses
97    pub const REMOVE_ADAPTER_AUTHORIZED_CONTEXT: Item<u64> = Item::new("rm_a_auth");
98}
99
100use cosmwasm_schema::QueryResponses;
101use cosmwasm_std::{Addr, Binary};
102use cw2::ContractVersion;
103
104use self::state::AccountInfo;
105use crate::{
106    manager::state::SuspensionStatus,
107    objects::{
108        account::AccountId, gov_type::GovernanceDetails, module::ModuleInfo,
109        nested_admin::TopLevelOwnerResponse, AssetEntry,
110    },
111};
112
113/// Manager Migrate Msg
114#[cosmwasm_schema::cw_serde]
115pub struct MigrateMsg {}
116
117/// Manager Instantiate Msg
118#[cosmwasm_schema::cw_serde]
119pub struct InstantiateMsg {
120    pub account_id: AccountId,
121    pub owner: GovernanceDetails<String>,
122    pub proxy_addr: String,
123    pub version_control_address: String,
124    pub module_factory_address: String,
125    pub name: String,
126    pub description: Option<String>,
127    pub link: Option<String>,
128    // Optionally modules can be provided. They will be installed after account registration.
129    pub install_modules: Vec<ModuleInstallConfig>,
130}
131
132/// Callback message to set the dependencies after module upgrades.
133#[cosmwasm_schema::cw_serde]
134pub struct CallbackMsg {}
135
136/// Internal configuration actions accessible from the [`ExecuteMsg::UpdateInternalConfig`] message.
137#[cosmwasm_schema::cw_serde]
138#[non_exhaustive]
139pub enum InternalConfigAction {
140    /// Updates the [`state::ACCOUNT_MODULES`] map
141    /// Only callable by account factory or owner.
142    UpdateModuleAddresses {
143        to_add: Option<Vec<(String, String)>>,
144        to_remove: Option<Vec<String>>,
145    },
146}
147
148#[cosmwasm_schema::cw_serde]
149#[non_exhaustive]
150pub enum UpdateSubAccountAction {
151    /// Unregister sub-account
152    /// It will unregister sub-account from the state
153    /// Could be called only by the sub-account itself
154    UnregisterSubAccount { id: u32 },
155    /// Register sub-account
156    /// It will register new sub-account into the state
157    /// Could be called by the sub-account manager
158    /// Note: since it happens after the claim by this manager state won't have spam accounts
159    RegisterSubAccount { id: u32 },
160}
161
162/// Module info and init message
163#[non_exhaustive]
164#[cosmwasm_schema::cw_serde]
165pub struct ModuleInstallConfig {
166    pub module: ModuleInfo,
167    pub init_msg: Option<Binary>,
168}
169
170impl ModuleInstallConfig {
171    pub fn new(module: ModuleInfo, init_msg: Option<Binary>) -> Self {
172        Self { module, init_msg }
173    }
174}
175
176/// Manager execute messages
177#[cw_ownable::cw_ownable_execute]
178#[cosmwasm_schema::cw_serde]
179#[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))]
180pub enum ExecuteMsg {
181    /// Forward execution message to module
182    #[cfg_attr(feature = "interface", payable)]
183    ExecOnModule { module_id: String, exec_msg: Binary },
184    /// Update Abstract-specific configuration of the module.
185    /// Only callable by the account factory or owner.
186    UpdateInternalConfig(Binary),
187    /// Install module using module factory, callable by Owner
188    #[cfg_attr(feature = "interface", payable)]
189    InstallModules {
190        // Module information and Instantiate message to instantiate the contract
191        modules: Vec<ModuleInstallConfig>,
192    },
193    /// Uninstall a module given its ID.
194    UninstallModule { module_id: String },
195    /// Upgrade the module to a new version
196    /// If module is `abstract::manager` then the contract will do a self-migration.
197    Upgrade {
198        modules: Vec<(ModuleInfo, Option<Binary>)>,
199    },
200    /// Creates a sub-account on the account
201    #[cfg_attr(feature = "interface", payable)]
202    CreateSubAccount {
203        // Name of the sub-account
204        name: String,
205        // Description of the account
206        description: Option<String>,
207        // URL linked to the account
208        link: Option<String>,
209        // Optionally specify a base asset for the sub-account
210        base_asset: Option<AssetEntry>,
211        // optionally specify a namespace for the sub-account
212        namespace: Option<String>,
213        // Provide list of module to install after sub-account creation
214        install_modules: Vec<ModuleInstallConfig>,
215        /// If `None`, will create a new local account without asserting account-id.
216        ///
217        /// When provided: Signals the expected local Account Id. The tx will error if this does not match the account-id at runtime. Useful for instantiate2 address prediction.
218        account_id: Option<u32>,
219    },
220    /// Update info
221    UpdateInfo {
222        name: Option<String>,
223        description: Option<String>,
224        link: Option<String>,
225    },
226    /// Proposes a new Owner
227    /// The new owner has to claim ownership through the [`ExecuteMsg::UpdateOwnership`] message.
228    /// The claim action can be called by the new owner directly OR by the owner of a top-level account
229    /// if the new ownership structure is a sub-account.
230    ProposeOwner { owner: GovernanceDetails<String> },
231    /// Update account statuses
232    UpdateStatus { is_suspended: Option<bool> },
233    /// Update settings for the Account, including IBC enabled, etc.
234    UpdateSettings { ibc_enabled: Option<bool> },
235    /// Actions called by internal or external sub-accounts
236    UpdateSubAccount(UpdateSubAccountAction),
237    /// Callback endpoint
238    Callback(CallbackMsg),
239}
240
241/// Manager query messages
242#[cw_ownable::cw_ownable_query]
243#[cosmwasm_schema::cw_serde]
244#[derive(QueryResponses)]
245#[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))]
246pub enum QueryMsg {
247    /// Query the versions of modules installed on the account given their `ids`.
248    /// Returns [`ModuleVersionsResponse`]
249    #[returns(ModuleVersionsResponse)]
250    ModuleVersions { ids: Vec<String> },
251    /// Query the addresses of modules installed on the account given their `ids`.
252    /// Returns [`ModuleAddressesResponse`]
253    #[returns(ModuleAddressesResponse)]
254    ModuleAddresses { ids: Vec<String> },
255    /// Query information of all modules installed on the account.
256    /// Returns [`ModuleInfosResponse`]
257    #[returns(ModuleInfosResponse)]
258    ModuleInfos {
259        start_after: Option<String>,
260        limit: Option<u8>,
261    },
262    /// Query the manager's config.
263    /// Returns [`ConfigResponse`]
264    #[returns(ConfigResponse)]
265    Config {},
266    /// Query the Account info.
267    /// Returns [`InfoResponse`]
268    #[returns(InfoResponse)]
269    Info {},
270    /// Returns [`SubAccountIdsResponse`]
271    #[returns(SubAccountIdsResponse)]
272    SubAccountIds {
273        start_after: Option<u32>,
274        limit: Option<u8>,
275    },
276    /// Returns [`TopLevelOwnerResponse`]
277    #[returns(TopLevelOwnerResponse)]
278    TopLevelOwner {},
279}
280
281#[cosmwasm_schema::cw_serde]
282pub struct ModuleVersionsResponse {
283    pub versions: Vec<ContractVersion>,
284}
285
286#[cosmwasm_schema::cw_serde]
287pub struct ModuleAddressesResponse {
288    pub modules: Vec<(String, Addr)>,
289}
290
291#[cosmwasm_schema::cw_serde]
292pub struct ConfigResponse {
293    pub account_id: AccountId,
294    pub is_suspended: SuspensionStatus,
295    pub version_control_address: Addr,
296    pub module_factory_address: Addr,
297}
298
299#[cosmwasm_schema::cw_serde]
300pub struct InfoResponse {
301    pub info: AccountInfo<Addr>,
302}
303
304#[cosmwasm_schema::cw_serde]
305pub struct ManagerModuleInfo {
306    pub id: String,
307    pub version: ContractVersion,
308    pub address: Addr,
309}
310
311#[cosmwasm_schema::cw_serde]
312pub struct ModuleInfosResponse {
313    pub module_infos: Vec<ManagerModuleInfo>,
314}
315
316#[cosmwasm_schema::cw_serde]
317pub struct SubAccountIdsResponse {
318    pub sub_accounts: Vec<u32>,
319}