abstract_interface/native/
ans_host.rs1pub use abstract_std::ans_host::ExecuteMsgFns;
2use abstract_std::{
3 ans_host::*,
4 objects::{
5 pool_metadata::ResolvedPoolMetadata, AnsAsset, AnsEntryConvertor, AssetEntry, ChannelEntry,
6 ContractEntry, DexAssetPairing, LpToken, PoolMetadata, PoolReference, UniquePoolId,
7 },
8 ANS_HOST,
9};
10use cosmwasm_std::Uint128;
11use cw_address_like::AddressLike;
12use cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetInfoUnchecked, AssetUnchecked};
13use cw_orch::{interface, prelude::*};
14
15#[interface(InstantiateMsg, ExecuteMsg, QueryMsg, MigrateMsg)]
16pub struct AnsHost<Chain>;
17
18impl<Chain: CwEnv> cw_blob::interface::DeterministicInstantiation<Chain> for AnsHost<Chain> {}
19
20impl<Chain: CwEnv> AnsHost<Chain> {
21 pub fn balance(&self, addr: &Addr, asset: &AssetEntry) -> Result<Uint128, CwOrchError> {
22 let asset: AssetInfo = self.resolve(asset)?;
23 let chain = self.environment();
24 match asset {
25 AssetInfoBase::Native(denom) => chain
26 .balance(addr, Some(denom))
27 .map(|coins| coins[0].amount)
28 .map_err(Into::into),
29 AssetInfoBase::Cw20(cw20_addr) => {
30 let res: cw20::BalanceResponse = chain
31 .query(
32 &cw20::Cw20QueryMsg::Balance {
33 address: addr.to_string(),
34 },
35 &cw20_addr,
36 )
37 .map_err(Into::into)?;
38 Ok(res.balance)
39 }
40 _ => unimplemented!(),
41 }
42 }
43}
44
45impl<Chain: CwEnv> AnsHost<Chain> {
46 pub fn resolve<R: ClientResolve<Chain>>(&self, item: &R) -> Result<R::Output, CwOrchError> {
47 item.resolve(self)
48 }
49}
50
51impl<Chain: CwEnv> Uploadable for AnsHost<Chain> {
52 fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
53 Box::new(
54 ContractWrapper::new_with_empty(
55 ::ans_host::contract::execute,
56 ::ans_host::contract::instantiate,
57 ::ans_host::contract::query,
58 )
59 .with_migrate(::ans_host::contract::migrate),
60 )
61 }
62 fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
63 artifacts_dir_from_workspace!()
64 .find_wasm_path("ans_host")
65 .unwrap()
66 }
67}
68
69impl<Chain: CwEnv> AnsHost<Chain>
70where
71 TxResponse<Chain>: IndexResponse,
72{
73 pub fn load(chain: Chain, address: &Addr) -> Self {
74 let contract = cw_orch::contract::Contract::new(ANS_HOST, chain);
75 contract.set_address(address);
76 Self(contract)
77 }
78}
79
80pub trait ClientResolve<Chain: CwEnv> {
81 type Output;
83 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError>;
85}
86
87impl<Chain: CwEnv> ClientResolve<Chain> for AssetEntry {
90 type Output = AssetInfo;
91
92 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
93 let mut assets: AssetsResponse = ans_host.query(&QueryMsg::Assets {
94 names: vec![self.to_string()],
95 })?;
96 Ok(assets.assets.pop().unwrap().1)
97 }
98}
99
100impl<Chain: CwEnv> ClientResolve<Chain> for LpToken {
101 type Output = AssetInfo;
102
103 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
104 let asset_entry = AnsEntryConvertor::new(self.clone()).asset_entry();
105 asset_entry.resolve(ans_host)
106 }
107}
108
109impl<Chain: CwEnv> ClientResolve<Chain> for ContractEntry {
110 type Output = Addr;
111
112 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
113 let mut contracts: ContractsResponse = ans_host.query(&QueryMsg::Contracts {
114 entries: vec![self.clone()],
115 })?;
116 Ok(contracts.contracts.pop().unwrap().1)
117 }
118}
119
120impl<Chain: CwEnv> ClientResolve<Chain> for ChannelEntry {
121 type Output = String;
122
123 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
124 let mut channels: ChannelsResponse = ans_host.query(&QueryMsg::Channels {
125 entries: vec![self.clone()],
126 })?;
127 Ok(channels.channels.pop().unwrap().1)
128 }
129}
130
131impl<Chain: CwEnv> ClientResolve<Chain> for DexAssetPairing {
132 type Output = Vec<PoolReference>;
133
134 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
135 let mut pool_address_list: PoolAddressListResponse =
136 ans_host.query(&QueryMsg::PoolList {
137 filter: Some(AssetPairingFilter {
138 asset_pair: Some((self.asset_x().clone(), self.asset_y().clone())),
139 dex: Some(self.dex().to_owned()),
140 }),
141 start_after: None,
142 limit: None,
143 })?;
144 let found = pool_address_list
145 .pools
146 .pop()
147 .ok_or(CwOrchError::StdErr(format!(
148 "Pool reference for {self} not found"
149 )))?;
150 Ok(found.1.clone())
151 }
152}
153
154impl<Chain: CwEnv> ClientResolve<Chain> for UniquePoolId {
155 type Output = PoolMetadata;
156
157 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
158 let mut pool_metadatas: PoolMetadatasResponse =
159 ans_host.query(&QueryMsg::PoolMetadatas { ids: vec![*self] })?;
160 Ok(pool_metadatas.metadatas.pop().unwrap().1)
161 }
162}
163
164impl<Chain: CwEnv> ClientResolve<Chain> for AnsAsset {
165 type Output = Asset;
166
167 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
168 Ok(Asset::new(self.name.resolve(ans_host)?, self.amount))
169 }
170}
171
172impl<Chain: CwEnv, T: AddressLike> ClientResolve<Chain> for AssetInfoBase<T> {
173 type Output = AssetEntry;
174
175 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
176 let asset_info_unchecked = match self {
177 AssetInfoBase::Native(native) => AssetInfoUnchecked::native(native),
178 AssetInfoBase::Cw20(cw20) => AssetInfoUnchecked::cw20(cw20.to_string()),
179 _ => panic!("Not supported asset type"),
180 };
181 let mut assets: AssetInfosResponse = ans_host.query(&QueryMsg::AssetInfos {
182 infos: vec![asset_info_unchecked],
183 })?;
184 Ok(assets.infos.pop().unwrap().1)
185 }
186}
187
188impl<Chain: CwEnv> ClientResolve<Chain> for AssetUnchecked {
189 type Output = AnsAsset;
190
191 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
192 Ok(AnsAsset {
193 name: self.info.resolve(ans_host)?,
194 amount: self.amount,
195 })
196 }
197}
198
199impl<Chain: CwEnv> ClientResolve<Chain> for PoolMetadata {
200 type Output = ResolvedPoolMetadata;
201
202 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
203 Ok(ResolvedPoolMetadata {
204 assets: self.assets.resolve(ans_host)?,
205 dex: self.dex.clone(),
206 pool_type: self.pool_type,
207 })
208 }
209}
210
211impl<Chain: CwEnv, T> ClientResolve<Chain> for Vec<T>
212where
213 T: ClientResolve<Chain>,
214{
215 type Output = Vec<T::Output>;
216
217 fn resolve(&self, ans_host: &AnsHost<Chain>) -> Result<Self::Output, CwOrchError> {
218 self.iter().map(|entry| entry.resolve(ans_host)).collect()
219 }
220}