use crate::{Abstract, AbstractIbc};
use abstract_std::registry::QueryMsgFns;
use abstract_std::{
ans_host, ibc_client, ibc_host, module_factory, objects::module::ModuleInfo, registry, ACCOUNT,
};
use abstract_std::{ANS_HOST, IBC_CLIENT, IBC_HOST, MODULE_FACTORY, REGISTRY};
use cosmwasm_std::from_json;
use cw2::{ContractVersion, CONTRACT};
use cw_orch::{environment::Environment, prelude::*};
use semver::Version;
impl<T: CwEnv> Abstract<T> {
#[deprecated(note = "use migrate_if_version_changed instead")]
pub fn migrate_if_needed(&self) -> Result<bool, crate::AbstractInterfaceError> {
let module_factory = self
.module_factory
.upload_and_migrate_if_needed(&module_factory::MigrateMsg::Migrate {})?;
let registry = self
.registry
.upload_and_migrate_if_needed(®istry::MigrateMsg::Migrate {})?;
let ans_host = self
.ans_host
.upload_and_migrate_if_needed(&ans_host::MigrateMsg::Migrate {})?;
let account = self.account.upload_and_register_if_needed(&self.registry)?;
#[allow(deprecated)]
let ibc = self.ibc.migrate_if_needed()?;
self.registry.approve_any_abstract_modules()?;
Ok(module_factory.is_some() || registry.is_some() || ans_host.is_some() || account || ibc)
}
pub fn migrate_if_version_changed(&self) -> Result<bool, crate::AbstractInterfaceError> {
let mut has_migrated = false;
let mut natives_to_register = vec![];
if ::module_factory::contract::CONTRACT_VERSION
!= contract_version(&self.module_factory)?.version
{
let migration_result = self
.module_factory
.upload_and_migrate_if_needed(&module_factory::MigrateMsg::Migrate {})?;
if migration_result.is_some() {
has_migrated = true;
}
natives_to_register.push((
self.module_factory.as_instance(),
::module_factory::contract::CONTRACT_VERSION.to_string(),
));
}
if ::registry::contract::CONTRACT_VERSION != contract_version(&self.registry)?.version {
let migration_result = self
.registry
.upload_and_migrate_if_needed(®istry::MigrateMsg::Migrate {})?;
if migration_result.is_some() {
has_migrated = true;
}
natives_to_register.push((
self.registry.as_instance(),
::registry::contract::CONTRACT_VERSION.to_string(),
));
}
if ::ans_host::contract::CONTRACT_VERSION != contract_version(&self.ans_host)?.version {
let migration_result = self
.ans_host
.upload_and_migrate_if_needed(&ans_host::MigrateMsg::Migrate {})?;
if migration_result.is_some() {
has_migrated = true;
}
natives_to_register.push((
self.ans_host.as_instance(),
::ans_host::contract::CONTRACT_VERSION.to_string(),
));
}
let versions = self
.registry
.modules(vec![
ModuleInfo::from_id_latest(ACCOUNT)?,
ModuleInfo::from_id_latest(ACCOUNT)?,
])?
.modules;
if ::account::contract::CONTRACT_VERSION != versions[0].module.info.version.to_string()
&& self.account.upload_if_needed()?.is_some()
{
self.registry.register_account(
self.account.as_instance(),
::account::contract::CONTRACT_VERSION.to_string(),
)?;
has_migrated = true
}
if self.ibc.deploy_or_migrate_if_version_changed()? {
has_migrated = true;
natives_to_register.push((
self.ibc.client.as_instance(),
::ibc_client::contract::CONTRACT_VERSION.to_string(),
));
natives_to_register.push((
self.ibc.host.as_instance(),
::ibc_host::contract::CONTRACT_VERSION.to_string(),
));
}
self.registry.register_natives(natives_to_register)?;
self.registry.approve_any_abstract_modules()?;
Ok(has_migrated)
}
pub fn register_in_registry(&self) -> Result<(), crate::AbstractInterfaceError> {
let mut natives_to_register = vec![];
let modules = self
.registry
.modules(vec![
ModuleInfo::from_id_latest(MODULE_FACTORY)?,
ModuleInfo::from_id_latest(REGISTRY)?,
ModuleInfo::from_id_latest(ANS_HOST)?,
ModuleInfo::from_id_latest(IBC_CLIENT)?,
ModuleInfo::from_id_latest(IBC_HOST)?,
])?
.modules;
let module_factory_module = modules[0].module.clone();
let registry_module = modules[1].module.clone();
let ans_host_module = modules[2].module.clone();
let ibc_client_module = modules[3].module.clone();
let ibc_host_module = modules[4].module.clone();
if ::module_factory::contract::CONTRACT_VERSION
!= module_factory_module.info.version.to_string()
{
natives_to_register.push((
self.module_factory.as_instance(),
::module_factory::contract::CONTRACT_VERSION.to_string(),
));
}
if ::registry::contract::CONTRACT_VERSION != registry_module.info.version.to_string() {
natives_to_register.push((
self.registry.as_instance(),
::registry::contract::CONTRACT_VERSION.to_string(),
));
}
if ::ans_host::contract::CONTRACT_VERSION != ans_host_module.info.version.to_string() {
natives_to_register.push((
self.ans_host.as_instance(),
::ans_host::contract::CONTRACT_VERSION.to_string(),
));
}
if ::ibc_client::contract::CONTRACT_VERSION != ibc_client_module.info.version.to_string() {
natives_to_register.push((
self.ibc.client.as_instance(),
::ibc_client::contract::CONTRACT_VERSION.to_string(),
));
}
if ::ibc_host::contract::CONTRACT_VERSION != ibc_host_module.info.version.to_string() {
natives_to_register.push((
self.ibc.host.as_instance(),
::ibc_host::contract::CONTRACT_VERSION.to_string(),
));
}
self.registry.register_natives(natives_to_register)?;
self.registry.approve_any_abstract_modules()?;
Ok(())
}
}
fn contract_version<Chain: CwEnv, A: ContractInstance<Chain>>(
contract: &A,
) -> Result<ContractVersion, crate::AbstractInterfaceError> {
let wasm_querier = contract.environment().wasm_querier();
Ok(from_json(
wasm_querier
.raw_query(&contract.address()?, CONTRACT.as_slice().to_vec())
.unwrap(),
)?)
}
impl<Chain: CwEnv> AbstractIbc<Chain> {
#[deprecated(note = "use deploy_or_migrate_if_version_changed instead")]
pub fn migrate_if_needed(&self) -> Result<bool, crate::AbstractInterfaceError> {
let client = self
.client
.upload_and_migrate_if_needed(&ibc_client::MigrateMsg {})?;
let host = self
.host
.upload_and_migrate_if_needed(&ibc_host::MigrateMsg {})?;
Ok(client.is_some() || host.is_some())
}
pub fn deploy_or_migrate_if_version_changed(
&self,
) -> Result<bool, crate::AbstractInterfaceError> {
let ibc_client_cw2_version = contract_version(&self.client)?.version;
if ::ibc_client::contract::CONTRACT_VERSION == ibc_client_cw2_version {
return Ok(false);
}
self.client.upload_if_needed()?;
self.host.upload_if_needed()?;
if is_upgrade_breaking(
&ibc_client_cw2_version,
::ibc_client::contract::CONTRACT_VERSION,
) {
self.instantiate(&self.client.environment().sender_addr())?;
} else {
self.client
.migrate_if_needed(&ibc_client::MigrateMsg {})?
.expect("IBC client supposed to be migrated, but skipped instead");
self.host
.migrate_if_needed(&ibc_host::MigrateMsg {})?
.expect("IBC host supposed to be migrated, but skipped instead");
}
Ok(true)
}
}
fn is_upgrade_breaking(current_version: &str, new_version: &str) -> bool {
let version_req = semver::VersionReq::parse(current_version).unwrap();
let new_version = semver::Version::parse(new_version).unwrap();
let current_version = semver::Version::parse(current_version).unwrap();
!version_req.matches(&new_version)
|| (one_has_pre(&new_version, ¤t_version) && new_version != current_version)
}
fn one_has_pre(cmp: &Version, ver: &Version) -> bool {
!cmp.pre.is_empty() || !ver.pre.is_empty()
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn upgrade_breaking() {
assert!(is_upgrade_breaking("0.1.2", "0.2.0"));
assert!(is_upgrade_breaking("0.1.2-beta.1", "0.1.2"));
assert!(is_upgrade_breaking("1.2.3-beta.1", "1.2.3"));
assert!(is_upgrade_breaking("1.2.3", "1.2.4-beta.1"));
assert!(is_upgrade_breaking("1.2.3-beta.1", "1.2.3-beta.2"));
assert!(!is_upgrade_breaking("1.2.3", "1.3.0"));
assert!(!is_upgrade_breaking("0.1.2", "0.1.3"));
assert!(!is_upgrade_breaking("1.2.3", "1.2.4"));
assert!(!is_upgrade_breaking("1.2.3", "1.2.3"));
assert!(!is_upgrade_breaking("1.2.3-beta.1", "1.2.3-beta.1"));
assert!(!is_upgrade_breaking("0.25.0-beta.1", "0.25.0-beta.1"));
}
}