1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! # Module
//! The Module interface provides helper functions to execute functions on other modules installed on the Account.
use crate::core::objects::module::ModuleId;
use crate::{
features::{AccountIdentification, Dependencies},
AbstractSdkResult,
};
use abstract_core::manager::state::ACCOUNT_MODULES;
use cosmwasm_std::{Addr, Deps, QueryRequest, WasmQuery};
use cw2::{ContractVersion, CONTRACT};
/// Interact with other modules on the Account.
pub trait ModuleInterface: AccountIdentification + Dependencies {
/**
API for retrieving information about installed modules.
# Example
```
use abstract_sdk::prelude::*;
# use cosmwasm_std::testing::mock_dependencies;
# use abstract_sdk::mock_module::MockModule;
# let module = MockModule::new();
# let deps = mock_dependencies();
let modules: Modules<MockModule> = module.modules(deps.as_ref());
```
*/
fn modules<'a>(&'a self, deps: Deps<'a>) -> Modules<Self> {
Modules { base: self, deps }
}
}
impl<T> ModuleInterface for T where T: AccountIdentification + Dependencies {}
/**
API for retrieving information about installed modules.
# Example
```
use abstract_sdk::prelude::*;
# use cosmwasm_std::testing::mock_dependencies;
# use abstract_sdk::mock_module::MockModule;
# let module = MockModule::new();
# let deps = mock_dependencies();
let modules: Modules<MockModule> = module.modules(deps.as_ref());
```
*/
#[derive(Clone)]
pub struct Modules<'a, T: ModuleInterface> {
base: &'a T,
deps: Deps<'a>,
}
impl<'a, T: ModuleInterface> Modules<'a, T> {
/// Retrieve the address of an application in this Account.
/// This should **not** be used to execute messages on an `Api`.
/// Use `Modules::api_request(..)` instead.
pub fn module_address(&self, module_id: ModuleId) -> AbstractSdkResult<Addr> {
let manager_addr = self.base.manager_address(self.deps)?;
let maybe_module_addr =
ACCOUNT_MODULES.query(&self.deps.querier, manager_addr, module_id)?;
let Some(module_addr) = maybe_module_addr else {
return Err(crate::AbstractSdkError::MissingModule {
module: module_id.to_string(),
});
};
Ok(module_addr)
}
/// Retrieve the version of an application in this Account.
/// Note: this method makes use of the Cw2 query and may not coincide with the version of the
/// module listed in VersionControl.
pub fn module_version(&self, module_id: ModuleId) -> AbstractSdkResult<ContractVersion> {
let module_address = self.module_address(module_id)?;
let req = QueryRequest::Wasm(WasmQuery::Raw {
contract_addr: module_address.into(),
key: CONTRACT.as_slice().into(),
});
self.deps
.querier
.query::<ContractVersion>(&req)
.map_err(Into::into)
}
/// Assert that a module is a dependency of this module.
pub fn assert_module_dependency(&self, module_id: ModuleId) -> AbstractSdkResult<()> {
let is_dependency = Dependencies::dependencies(self.base)
.iter()
.map(|d| d.id)
.any(|x| x == module_id);
match is_dependency {
true => Ok(()),
false => Err(crate::AbstractSdkError::MissingDependency {
module: module_id.to_string(),
}),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::mock_module::*;
use abstract_testing::prelude::TEST_MODULE_ID;
use speculoos::prelude::*;
mod assert_module_dependency {
use super::*;
use cosmwasm_std::testing::*;
#[test]
fn should_return_ok_if_dependency() {
let deps = mock_dependencies();
let app = MockModule::new();
let mods = app.modules(deps.as_ref());
let res = mods.assert_module_dependency(TEST_MODULE_ID);
assert_that!(res).is_ok();
}
#[test]
fn should_return_err_if_not_dependency() {
let deps = mock_dependencies();
let app = MockModule::new();
let mods = app.modules(deps.as_ref());
let fake_module = "lol_no_chance";
let res = mods.assert_module_dependency(fake_module);
assert_that!(res).is_err().matches(|e| {
e.to_string()
.contains(&format!("{fake_module} is not a dependency"))
});
}
}
}