abstract_std/objects/
ans_host.rs

1use cosmwasm_std::{Addr, Deps, QuerierWrapper};
2use cw_asset::AssetInfo;
3use thiserror::Error;
4
5use super::{AssetEntry, ChannelEntry, ContractEntry};
6use crate::{
7    ans_host::{
8        state::{
9            ASSET_ADDRESSES, ASSET_PAIRINGS, CHANNELS, CONTRACT_ADDRESSES, POOL_METADATA,
10            REGISTERED_DEXES, REV_ASSET_ADDRESSES,
11        },
12        RegisteredDexesResponse,
13    },
14    native_addrs,
15    objects::{DexAssetPairing, PoolMetadata, PoolReference, UniquePoolId},
16    AbstractResult,
17};
18
19#[derive(Error, Debug, PartialEq)]
20pub enum AnsHostError {
21    // contract not found
22    #[error("Contract {contract} not found in ans_host {ans_host}.")]
23    ContractNotFound {
24        contract: ContractEntry,
25        ans_host: Addr,
26    },
27
28    // asset not found
29    #[error("Asset {asset} not found in ans_host {ans_host}.")]
30    AssetNotFound { asset: AssetEntry, ans_host: Addr },
31
32    // cw-asset not found
33    #[error("CW Asset {asset} not found in ans_host {ans_host}.")]
34    CwAssetNotFound { asset: AssetInfo, ans_host: Addr },
35
36    // channel not found
37    #[error("Channel {channel} not found in ans_host {ans_host}.")]
38    ChannelNotFound {
39        channel: ChannelEntry,
40        ans_host: Addr,
41    },
42
43    // dex asset Pairing not found
44    #[error("Asset pairing {pairing} not found in ans_host {ans_host}.")]
45    DexPairingNotFound {
46        pairing: DexAssetPairing,
47        ans_host: Addr,
48    },
49
50    // pool metadata not found
51    #[error("Pool metadata for pool {pool} not found in ans_host {ans_host}.")]
52    PoolMetadataNotFound { pool: UniquePoolId, ans_host: Addr },
53
54    #[error("Object {object} should be formatted {expected} but is {actual}")]
55    FormattingError {
56        object: String,
57        expected: String,
58        actual: String,
59    },
60
61    // Query method failed
62    #[error("Query during '{method_name}' failed: {error}")]
63    QueryFailed {
64        method_name: String,
65        error: cosmwasm_std::StdError,
66    },
67}
68
69pub type AnsHostResult<T> = Result<T, AnsHostError>;
70
71/// Struct that stores the ans-host contract address.
72/// Implements `AbstractNameService` feature
73#[cosmwasm_schema::cw_serde]
74pub struct AnsHost {
75    /// Address of the ans_host contract
76    pub address: Addr,
77}
78
79impl AnsHost {
80    /// Retrieve address of the ans host
81    pub fn new(deps: Deps, abstract_code_id: u64) -> AbstractResult<Self> {
82        let address = deps
83            .api
84            .addr_humanize(&native_addrs::ans_address(deps, abstract_code_id)?)?;
85        Ok(Self { address })
86    }
87    /// Raw Query to AnsHost contract
88    pub fn query_contracts(
89        &self,
90        querier: &QuerierWrapper,
91        contracts: &[ContractEntry],
92    ) -> AnsHostResult<Vec<Addr>> {
93        let mut resolved_contracts: Vec<Addr> = Vec::new();
94        // Query over keys
95        for key in contracts.iter() {
96            let result = self.query_contract(querier, key)?;
97            resolved_contracts.push(result);
98        }
99        Ok(resolved_contracts)
100    }
101
102    /// Raw query of a single contract Addr
103    #[function_name::named]
104    pub fn query_contract(
105        &self,
106        querier: &QuerierWrapper,
107        contract: &ContractEntry,
108    ) -> AnsHostResult<Addr> {
109        let result: Addr = CONTRACT_ADDRESSES
110            .query(querier, self.address.clone(), contract)
111            .map_err(|error| AnsHostError::QueryFailed {
112                method_name: function_name!().to_owned(),
113                error,
114            })?
115            .ok_or_else(|| AnsHostError::ContractNotFound {
116                contract: contract.clone(),
117                ans_host: self.address.clone(),
118            })?;
119        Ok(result)
120    }
121
122    /// Raw Query to AnsHost contract
123    pub fn query_assets(
124        &self,
125        querier: &QuerierWrapper,
126        assets: &[AssetEntry],
127    ) -> AnsHostResult<Vec<AssetInfo>> {
128        let mut resolved_assets = Vec::new();
129
130        for asset in assets.iter() {
131            let result = self.query_asset(querier, asset)?;
132            resolved_assets.push(result);
133        }
134        Ok(resolved_assets)
135    }
136
137    /// Raw query of a single AssetInfo
138    #[function_name::named]
139    pub fn query_asset(
140        &self,
141        querier: &QuerierWrapper,
142        asset: &AssetEntry,
143    ) -> AnsHostResult<AssetInfo> {
144        let result = ASSET_ADDRESSES
145            .query(querier, self.address.clone(), asset)
146            .map_err(|error| AnsHostError::QueryFailed {
147                method_name: function_name!().to_owned(),
148                error,
149            })?
150            .ok_or_else(|| AnsHostError::AssetNotFound {
151                asset: asset.clone(),
152                ans_host: self.address.clone(),
153            })?;
154        Ok(result)
155    }
156
157    /// Raw Query to AnsHost contract
158    pub fn query_assets_reverse(
159        &self,
160        querier: &QuerierWrapper,
161        assets: &[AssetInfo],
162    ) -> AnsHostResult<Vec<AssetEntry>> {
163        // AssetInfo does not implement PartialEq, so we can't use a Vec
164        let mut resolved_assets = vec![];
165
166        for asset in assets.iter() {
167            let result = self.query_asset_reverse(querier, asset)?;
168            resolved_assets.push(result);
169        }
170        Ok(resolved_assets)
171    }
172
173    /// Raw query of a single AssetEntry
174    #[function_name::named]
175    pub fn query_asset_reverse(
176        &self,
177        querier: &QuerierWrapper,
178        asset: &AssetInfo,
179    ) -> AnsHostResult<AssetEntry> {
180        let result = REV_ASSET_ADDRESSES
181            .query(querier, self.address.clone(), asset)
182            .map_err(|error| AnsHostError::QueryFailed {
183                method_name: function_name!().to_owned(),
184                error,
185            })?
186            .ok_or_else(|| AnsHostError::CwAssetNotFound {
187                asset: asset.clone(),
188                ans_host: self.address.clone(),
189            })?;
190        Ok(result)
191    }
192
193    /// Raw query of a single channel Addr
194    #[function_name::named]
195    pub fn query_channel(
196        &self,
197        querier: &QuerierWrapper,
198        channel: &ChannelEntry,
199    ) -> AnsHostResult<String> {
200        let result: String = CHANNELS
201            .query(querier, self.address.clone(), channel)
202            .map_err(|error| AnsHostError::QueryFailed {
203                method_name: function_name!().to_owned(),
204                error,
205            })?
206            .ok_or_else(|| AnsHostError::ChannelNotFound {
207                channel: channel.clone(),
208                ans_host: self.address.clone(),
209            })?;
210        // Addresses are checked when stored.
211        Ok(result)
212    }
213
214    /// Raw query of a single asset pairing
215    #[function_name::named]
216    pub fn query_asset_pairing(
217        &self,
218        querier: &QuerierWrapper,
219        dex_asset_pairing: &DexAssetPairing,
220    ) -> AnsHostResult<Vec<PoolReference>> {
221        let result: Vec<PoolReference> = ASSET_PAIRINGS
222            .query(querier, self.address.clone(), dex_asset_pairing)
223            .map_err(|error| AnsHostError::QueryFailed {
224                method_name: function_name!().to_owned(),
225                error,
226            })?
227            .ok_or_else(|| AnsHostError::DexPairingNotFound {
228                pairing: dex_asset_pairing.clone(),
229                ans_host: self.address.clone(),
230            })?;
231        Ok(result)
232    }
233
234    #[function_name::named]
235    pub fn query_pool_metadata(
236        &self,
237        querier: &QuerierWrapper,
238        pool_id: UniquePoolId,
239    ) -> AnsHostResult<PoolMetadata> {
240        let result: PoolMetadata = POOL_METADATA
241            .query(querier, self.address.clone(), pool_id)
242            .map_err(|error| AnsHostError::QueryFailed {
243                method_name: function_name!().to_owned(),
244                error,
245            })?
246            .ok_or_else(|| AnsHostError::PoolMetadataNotFound {
247                pool: pool_id,
248                ans_host: self.address.clone(),
249            })?;
250        Ok(result)
251    }
252
253    #[function_name::named]
254    pub fn query_registered_dexes(
255        &self,
256        querier: &QuerierWrapper,
257    ) -> AnsHostResult<RegisteredDexesResponse> {
258        let dexes = REGISTERED_DEXES
259            .query(querier, self.address.clone())
260            .map_err(|error| AnsHostError::QueryFailed {
261                method_name: function_name!().to_owned(),
262                error,
263            })?;
264        Ok(RegisteredDexesResponse { dexes })
265    }
266}