use abstract_std::{
manager::ModuleInstallConfig,
objects::{
module::{ModuleInfo, ModuleVersion},
AccountId,
},
};
use cosmwasm_std::to_json_binary;
use cw_orch::{
environment::Environment,
prelude::{CwOrchError::StdErr, *},
};
use semver::Version;
use serde::Serialize;
use crate::Abstract;
pub trait RegisteredModule {
type InitMsg: Serialize;
fn module_id<'a>() -> &'a str;
fn module_version<'a>() -> &'a str;
fn installed_module_contract_id(account_id: &AccountId) -> String {
format!("{}-{}", Self::module_id(), account_id)
}
}
pub trait DependencyCreation {
type DependenciesConfig;
#[allow(unused_variables)]
fn dependency_install_configs(
configuration: Self::DependenciesConfig,
) -> Result<Vec<ModuleInstallConfig>, crate::AbstractInterfaceError> {
Ok(vec![])
}
}
pub trait InstallConfig: RegisteredModule {
fn module_info() -> Result<ModuleInfo, crate::AbstractInterfaceError> {
ModuleInfo::from_id(Self::module_id(), Self::module_version().into()).map_err(Into::into)
}
fn install_config(
init_msg: &Self::InitMsg,
) -> Result<ModuleInstallConfig, crate::AbstractInterfaceError> {
Ok(ModuleInstallConfig::new(
Self::module_info()?,
Some(to_json_binary(init_msg)?),
))
}
}
impl<T> InstallConfig for T where T: RegisteredModule {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeployStrategy {
Error,
Try,
Force,
}
pub trait AdapterDeployer<Chain: CwEnv, CustomInitMsg: Serialize>: ContractInstance<Chain>
+ CwOrchInstantiate<Chain, InstantiateMsg = abstract_std::adapter::InstantiateMsg<CustomInitMsg>>
+ Uploadable
+ Sized
{
fn deploy(
&self,
version: Version,
custom_init_msg: CustomInitMsg,
strategy: DeployStrategy,
) -> Result<(), crate::AbstractInterfaceError> {
let abstr = Abstract::load_from(self.environment().to_owned())?;
let vc_has_module = || {
abstr
.version_control
.registered_or_pending_module(
ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
.unwrap(),
)
.and_then(|module| module.reference.unwrap_adapter().map_err(Into::into))
};
match strategy {
DeployStrategy::Error => {
if vc_has_module().is_ok() {
return Err(StdErr(format!(
"Adapter {} already exists with version {}",
self.id(),
version
))
.into());
}
}
DeployStrategy::Try => {
if vc_has_module().is_ok() {
return Ok(());
}
}
DeployStrategy::Force => {}
}
self.upload_if_needed()?;
let init_msg = abstract_std::adapter::InstantiateMsg {
module: custom_init_msg,
base: abstract_std::adapter::BaseInstantiateMsg {
ans_host_address: abstr.ans_host.address()?.into(),
version_control_address: abstr.version_control.address()?.into(),
},
};
self.instantiate(&init_msg, None, None)?;
abstr
.version_control
.register_adapters(vec![(self.as_instance(), version.to_string())])?;
Ok(())
}
}
pub trait AppDeployer<Chain: CwEnv>: Sized + Uploadable + ContractInstance<Chain> {
fn deploy(
&self,
version: Version,
strategy: DeployStrategy,
) -> Result<(), crate::AbstractInterfaceError> {
let abstr = Abstract::<Chain>::load_from(self.environment().to_owned())?;
let vc_has_module = || {
abstr
.version_control
.registered_or_pending_module(
ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
.unwrap(),
)
.and_then(|module| module.reference.unwrap_app().map_err(Into::into))
};
match strategy {
DeployStrategy::Error => {
if vc_has_module().is_ok() {
return Err(StdErr(format!(
"App {} already exists with version {}",
self.id(),
version
))
.into());
}
}
DeployStrategy::Try => {
if vc_has_module().is_ok() {
return Ok(());
}
}
DeployStrategy::Force => {}
}
self.upload_if_needed()?;
abstr
.version_control
.register_apps(vec![(self.as_instance(), version.to_string())])?;
Ok(())
}
}
pub trait StandaloneDeployer<Chain: CwEnv>: Sized + Uploadable + ContractInstance<Chain> {
fn deploy(
&self,
version: Version,
strategy: DeployStrategy,
) -> Result<(), crate::AbstractInterfaceError> {
let abstr = Abstract::<Chain>::load_from(self.environment().to_owned())?;
let vc_has_module = || {
abstr
.version_control
.registered_or_pending_module(
ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
.unwrap(),
)
.and_then(|module| module.reference.unwrap_standalone().map_err(Into::into))
};
match strategy {
DeployStrategy::Error => {
if vc_has_module().is_ok() {
return Err(StdErr(format!(
"Standalone {} already exists with version {}",
self.id(),
version
))
.into());
}
}
DeployStrategy::Try => {
if vc_has_module().is_ok() {
return Ok(());
}
}
DeployStrategy::Force => {}
}
self.upload_if_needed()?;
abstr
.version_control
.register_standalones(vec![(self.as_instance(), version.to_string())])?;
Ok(())
}
}