use abstract_std::{
objects::{version_control::VersionControlContract, AccountId},
version_control::AccountBase,
};
use cosmwasm_std::{Addr, Deps};
use super::{AbstractApi, ApiIdentification};
use crate::{
cw_helpers::ApiQuery,
features::{AbstractRegistryAccess, ModuleIdentification},
AbstractSdkResult,
};
pub trait AccountVerification: AbstractRegistryAccess + ModuleIdentification {
fn account_registry<'a>(&'a self, deps: Deps<'a>) -> AbstractSdkResult<AccountRegistry<Self>> {
let vc = self.abstract_registry(deps)?;
Ok(AccountRegistry {
base: self,
deps,
vc,
})
}
}
impl<T> AccountVerification for T where T: AbstractRegistryAccess + ModuleIdentification {}
impl<'a, T: AccountVerification> AbstractApi<T> for AccountRegistry<'a, T> {
fn base(&self) -> &T {
self.base
}
fn deps(&self) -> Deps {
self.deps
}
}
impl<'a, T: AccountVerification> ApiIdentification for AccountRegistry<'a, T> {
fn api_id() -> String {
"AccountRegistry".to_owned()
}
}
#[derive(Clone)]
pub struct AccountRegistry<'a, T: AccountVerification> {
base: &'a T,
deps: Deps<'a>,
vc: VersionControlContract,
}
impl<'a, T: AccountVerification> AccountRegistry<'a, T> {
pub fn assert_manager(&self, maybe_manager: &Addr) -> AbstractSdkResult<AccountBase> {
self.vc
.assert_manager(maybe_manager, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn assert_proxy(&self, maybe_proxy: &Addr) -> AbstractSdkResult<AccountBase> {
self.vc
.assert_proxy(maybe_proxy, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn proxy_address(&self, account_id: &AccountId) -> AbstractSdkResult<Addr> {
self.account_base(account_id)
.map(|account_base| account_base.proxy)
}
pub fn manager_address(&self, account_id: &AccountId) -> AbstractSdkResult<Addr> {
self.account_base(account_id)
.map(|account_base| account_base.manager)
}
pub fn account_base(&self, account_id: &AccountId) -> AbstractSdkResult<AccountBase> {
self.vc
.account_base(account_id, &self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
pub fn account_id(&self, maybe_core_contract_addr: &Addr) -> AbstractSdkResult<AccountId> {
self.vc
.account_id(maybe_core_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.vc
.namespace_registration_fee(&self.deps.querier)
.map_err(|error| self.wrap_query_error(error))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::AbstractSdkError;
use abstract_std::{
objects::{account::AccountTrace, module::ModuleId, version_control::VersionControlError},
proxy::state::ACCOUNT_ID,
version_control::state::ACCOUNT_ADDRESSES,
};
use abstract_testing::prelude::*;
use cosmwasm_std::testing::*;
use speculoos::prelude::*;
struct MockBinding;
impl AbstractRegistryAccess for MockBinding {
fn abstract_registry(&self, _deps: Deps) -> AbstractSdkResult<VersionControlContract> {
Ok(VersionControlContract::new(Addr::unchecked(
TEST_VERSION_CONTROL,
)))
}
}
impl ModuleIdentification for MockBinding {
fn module_id(&self) -> ModuleId<'static> {
ModuleId::from("module")
}
}
pub const SECOND_TEST_ACCOUNT_ID: AccountId = AccountId::const_new(2, AccountTrace::Local);
mod assert_proxy {
use super::*;
#[test]
fn not_proxy_fails() {
let mut deps = mock_dependencies();
deps.querier = mocked_account_querier_builder()
.account("not_manager", "not_proxy", TEST_ACCOUNT_ID)
.account(TEST_MANAGER, TEST_PROXY, SECOND_TEST_ACCOUNT_ID)
.builder()
.with_contract_item("not_proxy", ACCOUNT_ID, &SECOND_TEST_ACCOUNT_ID)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_proxy(&Addr::unchecked("not_proxy"));
assert_that!(res)
.is_err()
.matches(|e| matches!(e, AbstractSdkError::ApiQuery { .. }))
.matches(|e| e.to_string().contains("not_proxy"));
}
#[test]
fn inactive_account_fails() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_PROXY, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_key(TEST_VERSION_CONTROL, ACCOUNT_ADDRESSES, &TEST_ACCOUNT_ID)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_proxy(&Addr::unchecked(TEST_PROXY));
assert_that!(res)
.is_err()
.matches(|e| matches!(e, AbstractSdkError::ApiQuery { .. }))
.matches(|e| {
e.to_string().contains(
&VersionControlError::UnknownAccountId {
account_id: TEST_ACCOUNT_ID,
registry_addr: Addr::unchecked(TEST_VERSION_CONTROL),
}
.to_string(),
)
});
}
#[test]
fn returns_core() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_PROXY, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_entry(
TEST_VERSION_CONTROL,
ACCOUNT_ADDRESSES,
(&TEST_ACCOUNT_ID, test_account_base()),
)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_proxy(&Addr::unchecked(TEST_PROXY));
assert_that!(res).is_ok().is_equal_to(test_account_base());
}
#[test]
fn errors_when_not_manager_of_returned_os() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_PROXY, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_entry(
TEST_VERSION_CONTROL,
ACCOUNT_ADDRESSES,
(
&TEST_ACCOUNT_ID,
AccountBase {
manager: Addr::unchecked(TEST_MANAGER),
proxy: Addr::unchecked("not_poxry"),
},
),
)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_proxy(&Addr::unchecked(TEST_PROXY));
assert_that!(res)
.is_err()
.matches(|e| e.to_string().contains("not the Proxy"));
}
}
mod assert_manager {
use super::*;
#[test]
fn not_manager_fails() {
let mut deps = mock_dependencies();
deps.querier = mocked_account_querier_builder()
.account("not_manager", "not_proxy", TEST_ACCOUNT_ID)
.account(TEST_MANAGER, TEST_PROXY, SECOND_TEST_ACCOUNT_ID)
.builder()
.with_contract_item("not_manager", ACCOUNT_ID, &SECOND_TEST_ACCOUNT_ID)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_manager(&Addr::unchecked("not_manager"));
assert_that!(res)
.is_err()
.matches(|e| matches!(e, AbstractSdkError::ApiQuery { .. }))
.matches(|e| e.to_string().contains("not_manager is not the Manager"));
}
#[test]
fn inactive_account_fails() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_MANAGER, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_key(TEST_VERSION_CONTROL, ACCOUNT_ADDRESSES, &TEST_ACCOUNT_ID)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_manager(&Addr::unchecked(TEST_MANAGER));
assert_that!(res)
.is_err()
.matches(|e| matches!(e, AbstractSdkError::ApiQuery { .. }))
.matches(|e| {
e.to_string().contains(
&VersionControlError::UnknownAccountId {
account_id: TEST_ACCOUNT_ID,
registry_addr: Addr::unchecked(TEST_VERSION_CONTROL),
}
.to_string(),
)
});
}
#[test]
fn returns_core() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_MANAGER, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_entry(
TEST_VERSION_CONTROL,
ACCOUNT_ADDRESSES,
(&TEST_ACCOUNT_ID, test_account_base()),
)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_manager(&Addr::unchecked(TEST_MANAGER));
assert_that!(res).is_ok().is_equal_to(test_account_base());
}
#[test]
fn errors_when_not_manager_of_returned_os() {
let mut deps = mock_dependencies();
deps.querier = MockQuerierBuilder::default()
.with_contract_item(TEST_MANAGER, ACCOUNT_ID, &TEST_ACCOUNT_ID)
.with_contract_map_entry(
TEST_VERSION_CONTROL,
ACCOUNT_ADDRESSES,
(
&TEST_ACCOUNT_ID,
AccountBase {
manager: Addr::unchecked("not_manager"),
proxy: Addr::unchecked(TEST_PROXY),
},
),
)
.build();
let binding = MockBinding;
let res = binding
.account_registry(deps.as_ref())
.unwrap()
.assert_manager(&Addr::unchecked(TEST_MANAGER));
assert_that!(res)
.is_err()
.matches(|e| matches!(e, AbstractSdkError::ApiQuery { .. }))
.matches(|e| {
e.to_string().contains(
&VersionControlError::NotManager(
Addr::unchecked(TEST_MANAGER),
TEST_ACCOUNT_ID,
)
.to_string(),
)
});
}
}
}