abstract_std/native/
registry.rs

1//! # Registry
2//!
3//! `abstract_std::registry` stores chain-specific code-ids, addresses and an account_id map.
4//!
5//! ## Description
6//! Code-ids and api-contract addresses are stored on this address. This data can not be changed and allows for complex factory logic.
7//! Both code-ids and addresses are stored on a per-module version basis which allows users to easily upgrade their modules.
8//!
9//! An internal account-id store provides external verification for accounts.  
10
11pub type ModuleMapEntry = (ModuleInfo, ModuleReference);
12
13/// Contains configuration info of registry.
14#[cosmwasm_schema::cw_serde]
15pub struct Config {
16    pub security_enabled: bool,
17    pub namespace_registration_fee: Option<Coin>,
18}
19
20pub mod state {
21    use cw_storage_plus::{Item, Map};
22
23    use super::{Account, Config, ModuleConfiguration, ModuleDefaultConfiguration};
24    use crate::objects::{
25        account::{AccountId, AccountSequence},
26        module::ModuleInfo,
27        module_reference::ModuleReference,
28        namespace::Namespace,
29        storage_namespaces::{self},
30    };
31
32    pub const CONFIG: Item<Config> = Item::new(storage_namespaces::CONFIG_STORAGE_KEY);
33
34    // Modules waiting for approvals
35    pub const PENDING_MODULES: Map<&ModuleInfo, ModuleReference> =
36        Map::new(storage_namespaces::registry::PENDING_MODULES);
37    // We can iterate over the map giving just the prefix to get all the versions
38    pub const REGISTERED_MODULES: Map<&ModuleInfo, ModuleReference> =
39        Map::new(storage_namespaces::registry::REGISTERED_MODULES);
40    // Reverse map for module info of standalone modules
41    pub const STANDALONE_INFOS: Map<u64, ModuleInfo> =
42        Map::new(storage_namespaces::registry::STANDALONE_INFOS);
43    // Reverse map for module info of service modules
44    pub const SERVICE_INFOS: Map<&cosmwasm_std::Addr, ModuleInfo> =
45        Map::new(storage_namespaces::registry::SERVICE_INFOS);
46    // Yanked Modules
47    pub const YANKED_MODULES: Map<&ModuleInfo, ModuleReference> =
48        Map::new(storage_namespaces::registry::YANKED_MODULES);
49    // Modules Configuration
50    pub const MODULE_CONFIG: Map<&ModuleInfo, ModuleConfiguration> =
51        Map::new(storage_namespaces::registry::MODULE_CONFIG);
52    // Modules Default Configuration
53    pub const MODULE_DEFAULT_CONFIG: Map<(&Namespace, &str), ModuleDefaultConfiguration> =
54        Map::new(storage_namespaces::registry::MODULE_DEFAULT_CONFIG);
55    /// Maps Account ID to the address of its core contracts
56    pub const ACCOUNT_ADDRESSES: Map<&AccountId, Account> =
57        Map::new(storage_namespaces::registry::ACCOUNT_ADDRESSES);
58    /// Account sequences
59    pub const LOCAL_ACCOUNT_SEQUENCE: Item<AccountSequence> =
60        Item::new(storage_namespaces::registry::LOCAL_ACCOUNT_SEQUENCE);
61    pub const NAMESPACES: Map<&Namespace, AccountId> =
62        Map::new(storage_namespaces::registry::NAMESPACES);
63    pub const REV_NAMESPACES: Map<&AccountId, Namespace> =
64        Map::new(storage_namespaces::registry::REV_NAMESPACES);
65}
66
67use cosmwasm_schema::QueryResponses;
68use cosmwasm_std::{Addr, Api, Coin, Storage};
69use cw_clearable::Clearable;
70
71use self::state::{MODULE_CONFIG, MODULE_DEFAULT_CONFIG};
72use crate::objects::{
73    account::AccountId,
74    module::{Module, ModuleInfo, ModuleMetadata, ModuleStatus, Monetization},
75    module_reference::ModuleReference,
76    namespace::Namespace,
77};
78
79/// Contains the minimal Abstract Account contract addresses.
80#[cosmwasm_schema::cw_serde]
81pub struct Account<T = Addr>(T);
82
83impl<T> Account<T> {
84    pub fn new(addr: T) -> Self {
85        Self(addr)
86    }
87}
88
89impl Account<String> {
90    pub fn verify(self, api: &dyn Api) -> cosmwasm_std::StdResult<Account<Addr>> {
91        let addr = api.addr_validate(&self.0)?;
92        Ok(Account(addr))
93    }
94}
95
96impl Account {
97    pub fn addr(&self) -> &Addr {
98        &self.0
99    }
100
101    pub fn into_addr(self) -> Addr {
102        self.0
103    }
104}
105
106impl From<Account<Addr>> for Account<String> {
107    fn from(addr: Account<Addr>) -> Self {
108        Account(addr.0.to_string())
109    }
110}
111
112/// Registry Instantiate Msg
113#[cosmwasm_schema::cw_serde]
114pub struct InstantiateMsg {
115    pub admin: String,
116    /// allows users to directly register modules without going through approval
117    /// Also allows them to change the module reference of an existing module
118    /// Also allows to claim namespaces permisionlessly
119    /// SHOULD ONLY BE `true` FOR TESTING
120    pub security_enabled: Option<bool>,
121    pub namespace_registration_fee: Option<Coin>,
122}
123
124/// Registry Execute Msg
125#[cw_ownable::cw_ownable_execute]
126#[cosmwasm_schema::cw_serde]
127#[derive(cw_orch::ExecuteFns)]
128pub enum ExecuteMsg {
129    /// Remove some version of a module
130    RemoveModule { module: ModuleInfo },
131    /// Yank a version of a module so that it may not be installed
132    /// Only callable by Admin
133    YankModule { module: ModuleInfo },
134    /// Propose new modules to the version registry
135    /// Namespaces need to be claimed by the Account before proposing modules
136    /// Once proposed, the modules need to be approved by the Admin via [`ExecuteMsg::ApproveOrRejectModules`]
137    ProposeModules { modules: Vec<ModuleMapEntry> },
138    /// Sets the metadata configuration for a module.
139    /// Only callable by namespace admin
140    UpdateModuleConfiguration {
141        module_name: String,
142        namespace: Namespace,
143        update_module: UpdateModule,
144    },
145    /// Approve or reject modules
146    /// This takes the modules in the pending_modules map and
147    /// moves them to the registered_modules map or yanked_modules map
148    ApproveOrRejectModules {
149        approves: Vec<ModuleInfo>,
150        rejects: Vec<ModuleInfo>,
151    },
152    /// Claim namespaces
153    ClaimNamespace {
154        account_id: AccountId,
155        namespace: String,
156    },
157    /// Forgo namespace claims
158    /// Only admin or root user can call this
159    ForgoNamespace { namespaces: Vec<String> },
160    /// Register a new Account to the deployed Accounts.
161    /// Claims namespace if provided.  
162    /// Only new accounts can call this.
163    AddAccount {
164        namespace: Option<String>,
165        creator: String,
166    },
167    /// Updates configuration of the Registry contract
168    UpdateConfig {
169        /// Whether the contract allows direct module registration
170        security_enabled: Option<bool>,
171        /// The fee charged when registering a namespace
172        namespace_registration_fee: Option<Clearable<Coin>>,
173    },
174}
175
176#[non_exhaustive]
177#[cosmwasm_schema::cw_serde]
178pub enum UpdateModule {
179    /// Updates the default metadata for the module
180    Default { metadata: ModuleMetadata },
181    /// Update configuration for specified version
182    Versioned {
183        /// Module version
184        version: String,
185        /// Update the metadata for this version
186        metadata: Option<ModuleMetadata>,
187        /// Update the monetization for this version
188        monetization: Option<Monetization>,
189        /// Update the init_funds for this version
190        instantiation_funds: Option<Vec<Coin>>,
191    },
192}
193
194/// A ModuleFilter that mirrors the [`ModuleInfo`] struct.
195#[derive(Default)]
196#[cosmwasm_schema::cw_serde]
197pub struct ModuleFilter {
198    pub namespace: Option<String>,
199    pub name: Option<String>,
200    pub version: Option<String>,
201    pub status: Option<ModuleStatus>,
202}
203
204/// Registry Query Msg
205#[cw_ownable::cw_ownable_query]
206#[cosmwasm_schema::cw_serde]
207#[derive(QueryResponses, cw_orch::QueryFns)]
208pub enum QueryMsg {
209    /// Query Core of Accounts
210    /// Returns [`AccountsResponse`]
211    #[returns(AccountsResponse)]
212    Accounts { account_ids: Vec<AccountId> },
213    /// Queries module information
214    /// Modules that are yanked are not returned
215    /// Returns [`ModulesResponse`]
216    #[returns(ModulesResponse)]
217    Modules { infos: Vec<ModuleInfo> },
218    /// Queries namespaces for an account
219    /// Returns [`NamespacesResponse`]
220    #[returns(NamespacesResponse)]
221    Namespaces { accounts: Vec<AccountId> },
222    /// Queries information about the namespace
223    /// Returns [`NamespaceResponse`]
224    #[returns(NamespaceResponse)]
225    Namespace { namespace: Namespace },
226    /// Returns [`ConfigResponse`]
227    #[returns(ConfigResponse)]
228    Config {},
229    /// Returns [`AccountListResponse`]
230    #[returns(AccountListResponse)]
231    AccountList {
232        start_after: Option<AccountId>,
233        limit: Option<u8>,
234    },
235    /// Returns [`ModulesListResponse`]
236    #[returns(ModulesListResponse)]
237    ModuleList {
238        filter: Option<ModuleFilter>,
239        start_after: Option<ModuleInfo>,
240        limit: Option<u8>,
241    },
242    /// Returns [`NamespaceListResponse`]
243    #[returns(NamespaceListResponse)]
244    NamespaceList {
245        start_after: Option<String>,
246        limit: Option<u8>,
247    },
248}
249
250#[cosmwasm_schema::cw_serde]
251pub struct AccountsResponse {
252    pub accounts: Vec<Account>,
253}
254
255#[cosmwasm_schema::cw_serde]
256pub struct AccountListResponse {
257    pub accounts: Vec<(AccountId, Account)>,
258}
259
260#[cosmwasm_schema::cw_serde]
261pub struct ModulesResponse {
262    pub modules: Vec<ModuleResponse>,
263}
264
265#[cosmwasm_schema::cw_serde]
266pub struct ModuleResponse {
267    pub module: Module,
268    pub config: ModuleConfiguration,
269}
270
271#[non_exhaustive]
272#[cosmwasm_schema::cw_serde]
273#[derive(Default)]
274pub struct ModuleConfiguration {
275    pub monetization: Monetization,
276    pub metadata: Option<ModuleMetadata>,
277    pub instantiation_funds: Vec<Coin>,
278}
279
280#[non_exhaustive]
281#[cosmwasm_schema::cw_serde]
282pub struct ModuleDefaultConfiguration {
283    pub metadata: ModuleMetadata,
284}
285
286impl ModuleDefaultConfiguration {
287    pub fn new(metadata: ModuleMetadata) -> Self {
288        Self { metadata }
289    }
290}
291
292impl ModuleConfiguration {
293    pub fn new(
294        monetization: Monetization,
295        metadata: Option<ModuleMetadata>,
296        instantiation_funds: Vec<Coin>,
297    ) -> Self {
298        Self {
299            monetization,
300            metadata,
301            instantiation_funds,
302        }
303    }
304
305    pub fn from_storage(
306        storage: &dyn Storage,
307        module: &ModuleInfo,
308    ) -> cosmwasm_std::StdResult<Self> {
309        let mut mod_cfg = MODULE_CONFIG.may_load(storage, module)?.unwrap_or_default();
310
311        if mod_cfg.metadata.is_none() {
312            // Destructure so we notice any field changes at compile time
313            if let Some(ModuleDefaultConfiguration { metadata }) =
314                MODULE_DEFAULT_CONFIG.may_load(storage, (&module.namespace, &module.name))?
315            {
316                mod_cfg.metadata = Some(metadata);
317            }
318        }
319
320        Ok(mod_cfg)
321    }
322}
323
324#[cosmwasm_schema::cw_serde]
325pub struct ModulesListResponse {
326    pub modules: Vec<ModuleResponse>,
327}
328
329#[cosmwasm_schema::cw_serde]
330pub enum NamespaceResponse {
331    Claimed(NamespaceInfo),
332    Unclaimed {},
333}
334
335impl NamespaceResponse {
336    pub fn unwrap(self) -> NamespaceInfo {
337        match self {
338            NamespaceResponse::Claimed(info) => info,
339            NamespaceResponse::Unclaimed {} => {
340                panic!("called `NamespaceResponse::unwrap()` on a `Unclaimed` value")
341            }
342        }
343    }
344}
345
346#[cosmwasm_schema::cw_serde]
347pub struct NamespaceInfo {
348    pub account_id: AccountId,
349    pub account: Account,
350}
351
352#[cosmwasm_schema::cw_serde]
353pub struct NamespacesResponse {
354    pub namespaces: Vec<(Namespace, AccountId)>,
355}
356
357#[cosmwasm_schema::cw_serde]
358pub struct NamespaceListResponse {
359    pub namespaces: Vec<(Namespace, AccountId)>,
360}
361
362#[cosmwasm_schema::cw_serde]
363pub struct ConfigResponse {
364    pub security_enabled: bool,
365    pub namespace_registration_fee: Option<Coin>,
366    pub local_account_sequence: u32,
367}
368
369#[cosmwasm_schema::cw_serde]
370pub enum MigrateMsg {
371    /// Migrating from blob contract
372    Instantiate(InstantiateMsg),
373    /// Migrating from previous version
374    Migrate {},
375}