use cosmwasm_std::{Addr, Deps, QuerierWrapper};
use thiserror::Error;
use super::{
module::{Module, ModuleInfo},
module_reference::ModuleReference,
namespace::Namespace,
AccountId,
};
use crate::{
account::state::ACCOUNT_ID,
native_addrs,
registry::{
state::{
ACCOUNT_ADDRESSES, CONFIG, NAMESPACES, REGISTERED_MODULES, SERVICE_INFOS,
STANDALONE_INFOS,
},
Account, ModuleConfiguration, ModuleResponse, ModulesResponse, NamespaceResponse,
NamespacesResponse, QueryMsg,
},
AbstractResult,
};
#[derive(Error, Debug, PartialEq)]
pub enum RegistryError {
#[error("Module {module} not found in version registry {registry_addr}.")]
ModuleNotFound { module: String, registry_addr: Addr },
#[error("Failed to query Account id on contract {contract_addr}. Please ensure that the contract is an Account contract.")]
FailedToQueryAccountId { contract_addr: Addr },
#[error("Standalone {code_id} not found in version registry {registry_addr}.")]
StandaloneNotFound { code_id: u64, registry_addr: Addr },
#[error("Unknown Account id {account_id} on registry {registry_addr}. Please ensure that you are using the correct Account id and registry address.")]
UnknownAccountId {
account_id: AccountId,
registry_addr: Addr,
},
#[error("Address {0} is not the valid account address of {1}.")]
NotAccount(Addr, AccountId),
#[error("Query during '{method_name}' failed: {error}")]
QueryFailed {
method_name: String,
error: cosmwasm_std::StdError,
},
#[error("Service {service_addr} not found in version registry {registry_addr}.")]
ServiceNotFound {
service_addr: Addr,
registry_addr: Addr,
},
#[error("The provided module {0} has an invalid module reference.")]
InvalidReference(ModuleInfo),
}
pub type RegistryResult<T> = Result<T, RegistryError>;
#[allow(rustdoc::broken_intra_doc_links)]
#[cosmwasm_schema::cw_serde]
pub struct RegistryContract {
pub address: Addr,
}
impl RegistryContract {
pub fn new(deps: Deps, abstract_code_id: u64) -> AbstractResult<Self> {
let address = deps
.api
.addr_humanize(&native_addrs::registry_address(deps, abstract_code_id)?)?;
Ok(Self { address })
}
#[function_name::named]
pub fn query_module_reference_raw(
&self,
module_info: &ModuleInfo,
querier: &QuerierWrapper,
) -> RegistryResult<ModuleReference> {
let module_reference = REGISTERED_MODULES
.query(querier, self.address.clone(), module_info)
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
module_reference.ok_or_else(|| RegistryError::ModuleNotFound {
module: module_info.to_string(),
registry_addr: self.address.clone(),
})
}
pub fn query_module(
&self,
module_info: ModuleInfo,
querier: &QuerierWrapper,
) -> RegistryResult<Module> {
Ok(self
.query_modules_configs(vec![module_info], querier)?
.swap_remove(0)
.module)
}
pub fn query_config(
&self,
module_info: ModuleInfo,
querier: &QuerierWrapper,
) -> RegistryResult<ModuleConfiguration> {
Ok(self
.query_modules_configs(vec![module_info], querier)?
.swap_remove(0)
.config)
}
#[function_name::named]
pub fn query_modules_configs(
&self,
infos: Vec<ModuleInfo>,
querier: &QuerierWrapper,
) -> RegistryResult<Vec<ModuleResponse>> {
let ModulesResponse { modules } = querier
.query_wasm_smart(self.address.to_string(), &QueryMsg::Modules { infos })
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(modules)
}
#[function_name::named]
pub fn query_namespace(
&self,
namespace: Namespace,
querier: &QuerierWrapper,
) -> RegistryResult<NamespaceResponse> {
let namespace_response: NamespaceResponse = querier
.query_wasm_smart(self.address.to_string(), &QueryMsg::Namespace { namespace })
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(namespace_response)
}
#[function_name::named]
pub fn query_namespace_raw(
&self,
namespace: Namespace,
querier: &QuerierWrapper,
) -> RegistryResult<Option<AccountId>> {
let namespace_response = NAMESPACES
.query(querier, self.address.clone(), &namespace)
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(namespace_response)
}
#[function_name::named]
pub fn query_namespaces(
&self,
accounts: Vec<AccountId>,
querier: &QuerierWrapper,
) -> RegistryResult<NamespacesResponse> {
let namespaces_response: NamespacesResponse = querier
.query_wasm_smart(self.address.to_string(), &QueryMsg::Namespaces { accounts })
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(namespaces_response)
}
#[function_name::named]
pub fn query_standalone_info_raw(
&self,
code_id: u64,
querier: &QuerierWrapper,
) -> RegistryResult<ModuleInfo> {
let module_info = STANDALONE_INFOS
.query(querier, self.address.clone(), code_id)
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
module_info.ok_or_else(|| RegistryError::StandaloneNotFound {
code_id,
registry_addr: self.address.clone(),
})
}
#[function_name::named]
pub fn query_service_info_raw(
&self,
service_addr: &Addr,
querier: &QuerierWrapper,
) -> RegistryResult<ModuleInfo> {
let module_info = SERVICE_INFOS
.query(querier, self.address.clone(), service_addr)
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
module_info.ok_or_else(|| RegistryError::ServiceNotFound {
service_addr: service_addr.clone(),
registry_addr: self.address.clone(),
})
}
pub fn unchecked_account_id(
&self,
maybe_core_contract_addr: &Addr,
querier: &QuerierWrapper,
) -> RegistryResult<AccountId> {
ACCOUNT_ID
.query(querier, maybe_core_contract_addr.clone())
.map_err(|_| RegistryError::FailedToQueryAccountId {
contract_addr: maybe_core_contract_addr.clone(),
})
}
pub fn account_id(
&self,
maybe_account_addr: &Addr,
querier: &QuerierWrapper,
) -> RegistryResult<AccountId> {
let self_reported_account_id = self.unchecked_account_id(maybe_account_addr, querier)?;
let account = self.account(&self_reported_account_id, querier)?;
if account.addr().ne(maybe_account_addr) {
Err(RegistryError::FailedToQueryAccountId {
contract_addr: maybe_account_addr.clone(),
})
} else {
Ok(self_reported_account_id)
}
}
#[function_name::named]
pub fn account(
&self,
account_id: &AccountId,
querier: &QuerierWrapper,
) -> RegistryResult<Account> {
let maybe_account = ACCOUNT_ADDRESSES
.query(querier, self.address.clone(), account_id)
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
maybe_account.ok_or_else(|| RegistryError::UnknownAccountId {
account_id: account_id.clone(),
registry_addr: self.address.clone(),
})
}
#[function_name::named]
pub fn namespace_registration_fee(
&self,
querier: &QuerierWrapper,
) -> RegistryResult<Option<cosmwasm_std::Coin>> {
let config = CONFIG
.query(querier, self.address.clone())
.map_err(|error| RegistryError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(config.namespace_registration_fee)
}
pub fn assert_account(
&self,
maybe_account: &Addr,
querier: &QuerierWrapper,
) -> RegistryResult<Account> {
let account_id = self.unchecked_account_id(maybe_account, querier)?;
let account = self.account(&account_id, querier)?;
if account.addr().ne(maybe_account) {
Err(RegistryError::NotAccount(maybe_account.clone(), account_id))
} else {
Ok(account)
}
}
}