use std::env;
pub use abstract_std::ans_host::ExecuteMsgFns;
use abstract_std::{
ans_host::*,
objects::{
pool_metadata::ResolvedPoolMetadata, AnsAsset, AnsEntryConvertor, AssetEntry, ChannelEntry,
ContractEntry, DexAssetPairing, LpToken, PoolMetadata, PoolReference, UniquePoolId,
},
ANS_HOST,
};
use cw_address_like::AddressLike;
use cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetInfoUnchecked, AssetUnchecked};
use cw_orch::{interface, prelude::*};
#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, MigrateMsg)]
pub struct AnsHost<Chain>;
impl<Chain: CwEnv> AnsHost<Chain> {
pub fn resolve<R: ClientResolve<Chain>>(&self, item: &R) -> Result<R::Output, CwOrchError> {
item.resolve(self)
}
}
impl<Chain: CwEnv> Uploadable for AnsHost<Chain> {
#[cfg(feature = "integration")]
fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
Box::new(
ContractWrapper::new_with_empty(
::ans_host::contract::execute,
::ans_host::contract::instantiate,
::ans_host::contract::query,
)
.with_migrate(::ans_host::contract::migrate),
)
}
fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
artifacts_dir_from_workspace!()
.find_wasm_path("ans_host")
.unwrap()
}
}
impl<Chain: CwEnv> AnsHost<Chain>
where
TxResponse<Chain>: IndexResponse,
{
pub fn load(chain: Chain, address: &Addr) -> Self {
let contract = cw_orch::contract::Contract::new(ANS_HOST, chain);
contract.set_address(address);
Self(contract)
}
}
pub trait ClientResolve<Chain: CwEnv> {
type Output;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError>;
}
impl<Chain: CwEnv> ClientResolve<Chain> for AssetEntry {
type Output = AssetInfo;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let mut assets: AssetsResponse = ans_host.query(&QueryMsg::Assets {
names: vec![self.to_string()],
})?;
Ok(assets.assets.pop().unwrap().1)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for LpToken {
type Output = AssetInfo;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let asset_entry = AnsEntryConvertor::new(self.clone()).asset_entry();
asset_entry.resolve(ans_host)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for ContractEntry {
type Output = Addr;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let mut contracts: ContractsResponse = ans_host.query(&QueryMsg::Contracts {
entries: vec![self.clone()],
})?;
Ok(contracts.contracts.pop().unwrap().1)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for ChannelEntry {
type Output = String;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let mut channels: ChannelsResponse = ans_host.query(&QueryMsg::Channels {
entries: vec![self.clone()],
})?;
Ok(channels.channels.pop().unwrap().1)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for DexAssetPairing {
type Output = Vec<PoolReference>;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let mut pool_address_list: PoolAddressListResponse =
ans_host.query(&QueryMsg::PoolList {
filter: Some(AssetPairingFilter {
asset_pair: Some((self.asset_x().clone(), self.asset_y().clone())),
dex: Some(self.dex().to_owned()),
}),
start_after: None,
limit: None,
})?;
let found = pool_address_list
.pools
.pop()
.ok_or(CwOrchError::StdErr(format!(
"Pool reference for {self} not found"
)))?;
Ok(found.1.clone())
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for UniquePoolId {
type Output = PoolMetadata;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let mut pool_metadatas: PoolMetadatasResponse =
ans_host.query(&QueryMsg::PoolMetadatas { ids: vec![*self] })?;
Ok(pool_metadatas.metadatas.pop().unwrap().1)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for AnsAsset {
type Output = Asset;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
Ok(Asset::new(self.name.resolve(ans_host)?, self.amount))
}
}
impl<Chain: CwEnv, T: AddressLike> ClientResolve<Chain> for AssetInfoBase<T> {
type Output = AssetEntry;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
let asset_info_unchecked = match self {
AssetInfoBase::Native(native) => AssetInfoUnchecked::native(native),
AssetInfoBase::Cw20(cw20) => AssetInfoUnchecked::cw20(cw20.to_string()),
_ => panic!("Not supported asset type"),
};
let mut assets: AssetInfosResponse = ans_host.query(&QueryMsg::AssetInfos {
infos: vec![asset_info_unchecked],
})?;
Ok(assets.infos.pop().unwrap().1)
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for AssetUnchecked {
type Output = AnsAsset;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
Ok(AnsAsset {
name: self.info.resolve(ans_host)?,
amount: self.amount,
})
}
}
impl<Chain: CwEnv> ClientResolve<Chain> for PoolMetadata {
type Output = ResolvedPoolMetadata;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
Ok(ResolvedPoolMetadata {
assets: self.assets.resolve(ans_host)?,
dex: self.dex.clone(),
pool_type: self.pool_type,
})
}
}
impl<Chain: CwEnv, T> ClientResolve<Chain> for Vec<T>
where
T: ClientResolve<Chain>,
{
type Output = Vec<T::Output>;
fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
self.iter().map(|entry| entry.resolve(ans_host)).collect()
}
}