use cosmwasm_std::{Addr, Deps, QuerierWrapper};
use cw_asset::AssetInfo;
use thiserror::Error;
use super::{AssetEntry, ChannelEntry, ContractEntry};
use crate::{
ans_host::{
state::{
ASSET_ADDRESSES, ASSET_PAIRINGS, CHANNELS, CONTRACT_ADDRESSES, POOL_METADATA,
REGISTERED_DEXES, REV_ASSET_ADDRESSES,
},
RegisteredDexesResponse,
},
native_addrs,
objects::{DexAssetPairing, PoolMetadata, PoolReference, UniquePoolId},
AbstractResult,
};
#[derive(Error, Debug, PartialEq)]
pub enum AnsHostError {
#[error("Contract {contract} not found in ans_host {ans_host}.")]
ContractNotFound {
contract: ContractEntry,
ans_host: Addr,
},
#[error("Asset {asset} not found in ans_host {ans_host}.")]
AssetNotFound { asset: AssetEntry, ans_host: Addr },
#[error("CW Asset {asset} not found in ans_host {ans_host}.")]
CwAssetNotFound { asset: AssetInfo, ans_host: Addr },
#[error("Channel {channel} not found in ans_host {ans_host}.")]
ChannelNotFound {
channel: ChannelEntry,
ans_host: Addr,
},
#[error("Asset pairing {pairing} not found in ans_host {ans_host}.")]
DexPairingNotFound {
pairing: DexAssetPairing,
ans_host: Addr,
},
#[error("Pool metadata for pool {pool} not found in ans_host {ans_host}.")]
PoolMetadataNotFound { pool: UniquePoolId, ans_host: Addr },
#[error("Object {object} should be formatted {expected} but is {actual}")]
FormattingError {
object: String,
expected: String,
actual: String,
},
#[error("Query during '{method_name}' failed: {error}")]
QueryFailed {
method_name: String,
error: cosmwasm_std::StdError,
},
}
pub type AnsHostResult<T> = Result<T, AnsHostError>;
#[cosmwasm_schema::cw_serde]
pub struct AnsHost {
pub address: Addr,
}
impl AnsHost {
pub fn new(deps: Deps, abstract_code_id: u64) -> AbstractResult<Self> {
let address = deps
.api
.addr_humanize(&native_addrs::ans_address(deps, abstract_code_id)?)?;
Ok(Self { address })
}
pub fn query_contracts(
&self,
querier: &QuerierWrapper,
contracts: &[ContractEntry],
) -> AnsHostResult<Vec<Addr>> {
let mut resolved_contracts: Vec<Addr> = Vec::new();
for key in contracts.iter() {
let result = self.query_contract(querier, key)?;
resolved_contracts.push(result);
}
Ok(resolved_contracts)
}
#[function_name::named]
pub fn query_contract(
&self,
querier: &QuerierWrapper,
contract: &ContractEntry,
) -> AnsHostResult<Addr> {
let result: Addr = CONTRACT_ADDRESSES
.query(querier, self.address.clone(), contract)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::ContractNotFound {
contract: contract.clone(),
ans_host: self.address.clone(),
})?;
Ok(result)
}
pub fn query_assets(
&self,
querier: &QuerierWrapper,
assets: &[AssetEntry],
) -> AnsHostResult<Vec<AssetInfo>> {
let mut resolved_assets = Vec::new();
for asset in assets.iter() {
let result = self.query_asset(querier, asset)?;
resolved_assets.push(result);
}
Ok(resolved_assets)
}
#[function_name::named]
pub fn query_asset(
&self,
querier: &QuerierWrapper,
asset: &AssetEntry,
) -> AnsHostResult<AssetInfo> {
let result = ASSET_ADDRESSES
.query(querier, self.address.clone(), asset)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::AssetNotFound {
asset: asset.clone(),
ans_host: self.address.clone(),
})?;
Ok(result)
}
pub fn query_assets_reverse(
&self,
querier: &QuerierWrapper,
assets: &[AssetInfo],
) -> AnsHostResult<Vec<AssetEntry>> {
let mut resolved_assets = vec![];
for asset in assets.iter() {
let result = self.query_asset_reverse(querier, asset)?;
resolved_assets.push(result);
}
Ok(resolved_assets)
}
#[function_name::named]
pub fn query_asset_reverse(
&self,
querier: &QuerierWrapper,
asset: &AssetInfo,
) -> AnsHostResult<AssetEntry> {
let result = REV_ASSET_ADDRESSES
.query(querier, self.address.clone(), asset)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::CwAssetNotFound {
asset: asset.clone(),
ans_host: self.address.clone(),
})?;
Ok(result)
}
#[function_name::named]
pub fn query_channel(
&self,
querier: &QuerierWrapper,
channel: &ChannelEntry,
) -> AnsHostResult<String> {
let result: String = CHANNELS
.query(querier, self.address.clone(), channel)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::ChannelNotFound {
channel: channel.clone(),
ans_host: self.address.clone(),
})?;
Ok(result)
}
#[function_name::named]
pub fn query_asset_pairing(
&self,
querier: &QuerierWrapper,
dex_asset_pairing: &DexAssetPairing,
) -> AnsHostResult<Vec<PoolReference>> {
let result: Vec<PoolReference> = ASSET_PAIRINGS
.query(querier, self.address.clone(), dex_asset_pairing)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::DexPairingNotFound {
pairing: dex_asset_pairing.clone(),
ans_host: self.address.clone(),
})?;
Ok(result)
}
#[function_name::named]
pub fn query_pool_metadata(
&self,
querier: &QuerierWrapper,
pool_id: UniquePoolId,
) -> AnsHostResult<PoolMetadata> {
let result: PoolMetadata = POOL_METADATA
.query(querier, self.address.clone(), pool_id)
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?
.ok_or_else(|| AnsHostError::PoolMetadataNotFound {
pool: pool_id,
ans_host: self.address.clone(),
})?;
Ok(result)
}
#[function_name::named]
pub fn query_registered_dexes(
&self,
querier: &QuerierWrapper,
) -> AnsHostResult<RegisteredDexesResponse> {
let dexes = REGISTERED_DEXES
.query(querier, self.address.clone())
.map_err(|error| AnsHostError::QueryFailed {
method_name: function_name!().to_owned(),
error,
})?;
Ok(RegisteredDexesResponse { dexes })
}
}