abstract_core/objects/
ans_host.rs

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