use abstract_std::{
objects::ownership::nested_admin::assert_account_calling_to_as_admin_is_self,
objects::{registry::RegistryContract, AccountId},
registry::Account,
};
use cosmwasm_std::{Addr, Deps, Env};
use super::AbstractApi;
use crate::{
cw_helpers::ApiQuery,
features::{AbstractRegistryAccess, ModuleIdentification},
AbstractSdkError, AbstractSdkResult,
};
pub trait AccountVerification: AbstractRegistryAccess + ModuleIdentification {
fn account_registry<'a>(
&'a self,
deps: Deps<'a>,
) -> AbstractSdkResult<AccountRegistry<'a, Self>> {
let vc = self.abstract_registry(deps)?;
Ok(AccountRegistry {
base: self,
deps,
registry: vc,
})
}
}
impl<T> AccountVerification for T where T: AbstractRegistryAccess + ModuleIdentification {}
impl<T: AccountVerification> AbstractApi<T> for AccountRegistry<'_, T> {
const API_ID: &'static str = "AccountRegistry";
fn base(&self) -> &T {
self.base
}
fn deps(&self) -> Deps {
self.deps
}
}
#[derive(Clone)]
pub struct AccountRegistry<'a, T: AccountVerification> {
base: &'a T,
deps: Deps<'a>,
registry: RegistryContract,
}
impl<T: AccountVerification> AccountRegistry<'_, T> {
pub fn assert_is_account(&self, maybe_account: &Addr) -> AbstractSdkResult<Account> {
self.registry
.assert_account(maybe_account, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn account(&self, account_id: &AccountId) -> AbstractSdkResult<Account> {
self.registry
.account(account_id, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn account_id(&self, maybe_account_contract_addr: &Addr) -> AbstractSdkResult<AccountId> {
self.registry
.account_id(maybe_account_contract_addr, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn namespace_registration_fee(&self) -> AbstractSdkResult<Option<cosmwasm_std::Coin>> {
self.registry
.namespace_registration_fee(&self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn assert_is_account_admin(
&self,
env: &Env,
maybe_account: &Addr,
) -> AbstractSdkResult<Account> {
let account = self.assert_is_account(maybe_account)?;
if !assert_account_calling_to_as_admin_is_self(&self.deps.querier, env, maybe_account) {
return Err(AbstractSdkError::OnlyAdmin {});
}
Ok(account)
}
}
#[cfg(test)]
mod test {
#![allow(clippy::needless_borrows_for_generic_args)]
use super::*;
use crate::{apis::traits::test::abstract_api_test, AbstractSdkError};
use abstract_std::{
account::state::ACCOUNT_ID,
objects::{account::AccountTrace, module::ModuleId, registry::RegistryError},
registry::{self, state::ACCOUNT_ADDRESSES},
};
use abstract_testing::prelude::*;
use cosmwasm_std::{testing::*, Coin};
struct MockBinding {}
impl AbstractRegistryAccess for MockBinding {
fn abstract_registry(&self, deps: Deps) -> AbstractSdkResult<RegistryContract> {
RegistryContract::new(deps, 1).map_err(Into::into)
}
}
impl ModuleIdentification for MockBinding {
fn module_id(&self) -> ModuleId<'static> {
ModuleId::from(TEST_MODULE_ID)
}
}
pub const SECOND_TEST_ACCOUNT_ID: AccountId = AccountId::const_new(2, AccountTrace::Local);
mod assert_account {
use super::*;
#[coverage_helper::test]
fn not_account_fails() {
let mut deps = mock_dependencies();
let not_account = Account::new(deps.api.addr_make("not_account"));
let base = test_account(deps.api);
deps.querier = MockQuerierBuilder::new(deps.api)
.account(¬_account, TEST_ACCOUNT_ID)
.account(&base, SECOND_TEST_ACCOUNT_ID)
.with_contract_item(not_account.addr(), ACCOUNT_ID, &SECOND_TEST_ACCOUNT_ID)
.build();
let binding = MockBinding {};
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_is_account(not_account.addr());
let expected_err = AbstractSdkError::ApiQuery {
api: AccountRegistry::<MockBinding>::api_id(),
module_id: binding.module_id().to_owned(),
error: Box::new(
RegistryError::NotAccount(not_account.addr().clone(), SECOND_TEST_ACCOUNT_ID)
.into(),
),
};
assert_eq!(res.unwrap_err(), expected_err);
}
#[coverage_helper::test]
fn inactive_account_fails() {
let mut deps = mock_dependencies();
let abstr = AbstractMockAddrs::new(deps.api);
deps.querier = MockQuerierBuilder::default()
.with_contract_item(abstr.account.addr(), ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_key(&abstr.registry, ACCOUNT_ADDRESSES, &TEST_ACCOUNT_ID)
.build();
let binding = MockBinding {};
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_is_account(abstr.account.addr());
let expected_err = AbstractSdkError::ApiQuery {
api: AccountRegistry::<MockBinding>::api_id(),
module_id: binding.module_id().to_owned(),
error: Box::new(
RegistryError::UnknownAccountId {
account_id: TEST_ACCOUNT_ID,
registry_addr: abstr.registry,
}
.into(),
),
};
assert_eq!(res.unwrap_err(), expected_err);
}
#[coverage_helper::test]
fn returns_account() {
let mut deps = mock_dependencies();
let account = test_account(deps.api);
deps.querier = abstract_mock_querier_builder(deps.api)
.account(&account, TEST_ACCOUNT_ID)
.build();
let binding = MockBinding {};
let registry = binding.account_registry(deps.as_ref()).unwrap();
let res = registry.assert_is_account(account.addr());
assert_eq!(res, Ok(account.clone()));
let account_id = registry.account_id(account.addr());
assert_eq!(account_id, Ok(TEST_ACCOUNT_ID));
}
}
#[coverage_helper::test]
fn namespace_fee() {
let mut deps = mock_dependencies();
deps.querier = abstract_mock_querier(deps.api);
let binding = MockBinding {};
{
let registry = binding.account_registry(deps.as_ref()).unwrap();
let res = registry.namespace_registration_fee();
assert_eq!(res, Ok(None));
}
let abstr = AbstractMockAddrs::new(deps.api);
deps.querier = abstract_mock_querier_builder(deps.api)
.with_contract_item(
&abstr.registry,
registry::state::CONFIG,
®istry::Config {
security_enabled: false,
namespace_registration_fee: Some(Coin::new(42_u128, "foo")),
},
)
.build();
let registry = binding.account_registry(deps.as_ref()).unwrap();
let res = registry.namespace_registration_fee();
assert_eq!(res, Ok(Some(Coin::new(42_u128, "foo"))));
}
#[coverage_helper::test]
fn abstract_api() {
let mut deps = mock_dependencies();
deps.querier = abstract_mock_querier(deps.api);
let module = MockBinding {};
let account_registry = module.account_registry(deps.as_ref()).unwrap();
abstract_api_test(account_registry);
}
}