whisky_provider/maestro/
fetcher.rs

1use super::models::account::StakeAccountInformation;
2use super::models::address::UtxosAtAddress;
3use super::models::asset::{AssetInformations, CollectionAssets};
4use super::models::protocol_parameters::ProtocolParameters;
5use super::models::transaction::TransactionDetails;
6use super::utils::*;
7use super::MaestroProvider;
8use async_trait::async_trait;
9use maestro_rust_sdk::client::block_info::BlockInfo as MBlockInfo;
10use maestro_rust_sdk::models::asset::AddressesHoldingAsset;
11use maestro_rust_sdk::models::epochs::EpochResp;
12
13use std::collections::HashMap;
14use whisky_common::models::{AccountInfo, Asset, BlockInfo, Protocol, TransactionInfo, UTxO};
15
16use whisky_common::*;
17
18#[async_trait]
19impl Fetcher for MaestroProvider {
20    async fn fetch_account_info(&self, address: &str) -> Result<AccountInfo, WError> {
21        let reward_address = if address.starts_with("addr") {
22            resolve_reward_address(address).map_err(WError::from_err(
23                "maestro::fetch_account_info resolve reward address",
24            ))?
25        } else {
26            address.to_string()
27        };
28
29        let url = format!("/accounts/{}", reward_address);
30
31        let resp = self
32            .maestro_client
33            .get(&url)
34            .await
35            .map_err(WError::from_err("maestro::fetch_account_info get"))?;
36
37        let stake_account_information: StakeAccountInformation = serde_json::from_str(&resp)
38            .map_err(WError::from_err("maestro::fetch_account_info type error"))?;
39
40        let account_info: AccountInfo =
41            account_information_to_account_info(stake_account_information.data);
42        Ok(account_info)
43    }
44
45    async fn fetch_address_utxos(
46        &self,
47        address: &str,
48        asset: Option<&str>,
49    ) -> Result<Vec<UTxO>, WError> {
50        let query_predicate =
51            if address.starts_with("addr_vkh") || address.starts_with("addr_shared_vkh") {
52                format!("/addresses/cred/{}", address)
53            } else {
54                format!("/addresses/{}", address)
55            };
56
57        let append_asset_string = match asset {
58            Some(a) => format!("&asset={}", a),
59            None => "".to_string(),
60        };
61
62        let url = format!("{}/utxos?count=100{}", query_predicate, append_asset_string,);
63
64        let resp = self
65            .maestro_client
66            .get(&url)
67            .await
68            .map_err(WError::from_err("maestro::fetch_address_utxos get"))?;
69
70        let mut utxos_at_address: UtxosAtAddress = serde_json::from_str(&resp)
71            .map_err(WError::from_err("maestro::fetch_address_utxos type error"))?;
72
73        let mut added_utxos: Vec<UTxO> = utxos_at_address
74            .data
75            .iter()
76            .map(to_utxo)
77            .collect::<Result<Vec<_>, _>>()
78            .map_err(WError::from_err("maestro::fetch_address_utxos to_utxo"))?;
79        println!("uxtos: {:?}", added_utxos);
80
81        while utxos_at_address.next_cursor.is_some() {
82            let append_cursor_string = format!(
83                "&cursor={}",
84                utxos_at_address.next_cursor.ok_or_else(WError::from_opt(
85                    "fetch_address_utxos",
86                    "append_cursor_string"
87                ))?
88            );
89            let url = format!(
90                "{}utxos?count=100{}{}",
91                query_predicate, append_asset_string, append_cursor_string
92            );
93            let resp = self
94                .maestro_client
95                .get(&url)
96                .await
97                .map_err(WError::from_err("maestro::fetch_address_utxos get"))?;
98            utxos_at_address = serde_json::from_str(&resp)
99                .map_err(WError::from_err("maestro::fetch_address_utxos type error"))?;
100            let uxtos: Vec<UTxO> = utxos_at_address
101                .data
102                .iter()
103                .map(to_utxo)
104                .collect::<Result<Vec<UTxO>, _>>()
105                .map_err(WError::from_err("maestro::fetch_address_utxos to_utxo"))?;
106            added_utxos.extend(uxtos);
107        }
108
109        Ok(added_utxos)
110    }
111
112    async fn fetch_asset_addresses(&self, asset: &str) -> Result<Vec<(String, String)>, WError> {
113        let (policy_id, asset_name) = Asset::unit_to_tuple(asset);
114        let url = format!("/assets/{}{}/addresses?count=100", &policy_id, &asset_name);
115
116        let resp = self
117            .maestro_client
118            .get(&url)
119            .await
120            .map_err(WError::from_err("maestro::fetch_asset_addresses get"))?;
121
122        let mut addresses_holding_asset: AddressesHoldingAsset = serde_json::from_str(&resp)
123            .map_err(WError::from_err(
124                "maestro::fetch_asset_addresses type error",
125            ))?;
126
127        let mut added_assets: Vec<(String, String)> = addresses_holding_asset
128            .data
129            .iter()
130            .map(|address_holding_asset| {
131                (
132                    address_holding_asset.address.clone(),
133                    address_holding_asset.amount.to_string(),
134                )
135            })
136            .collect();
137
138        while addresses_holding_asset.next_cursor.is_some() {
139            let append_cursor_string = format!(
140                "&cursor={}",
141                addresses_holding_asset
142                    .next_cursor
143                    .ok_or_else(WError::from_opt(
144                        "fetch_address_utxos",
145                        "append_cursor_string"
146                    ))?
147            );
148            let url = format!(
149                "/assets/{}{}/addresses?count=100{}",
150                &policy_id, &asset_name, append_cursor_string
151            );
152
153            let resp = self
154                .maestro_client
155                .get(&url)
156                .await
157                .map_err(WError::from_err("maestro::fetch_asset_addresses get"))?;
158            addresses_holding_asset = serde_json::from_str(&resp).map_err(WError::from_err(
159                "maestro::fetch_asset_addresses type error",
160            ))?;
161            let assets: Vec<(String, String)> = addresses_holding_asset
162                .data
163                .iter()
164                .map(|address_holding_asset| {
165                    (
166                        address_holding_asset.address.clone(),
167                        address_holding_asset.amount.to_string(),
168                    )
169                })
170                .collect();
171            added_assets.extend(assets);
172        }
173
174        Ok(added_assets)
175    }
176
177    async fn fetch_asset_metadata(
178        &self,
179        asset: &str,
180    ) -> Result<Option<HashMap<String, serde_json::Value>>, WError> {
181        let (policy_id, asset_name) = Asset::unit_to_tuple(asset);
182        let url = format!("/assets/{}{}", &policy_id, &asset_name);
183        let resp = self
184            .maestro_client
185            .get(&url)
186            .await
187            .map_err(WError::from_err("maestro::fetch_asset_metadata get"))?;
188
189        let asset_informations: AssetInformations = serde_json::from_str(&resp)
190            .map_err(WError::from_err("maestro::fetch_asset_metadata type error"))?;
191
192        let asset_metadata = asset_informations.data.latest_mint_tx_metadata;
193        Ok(asset_metadata)
194    }
195
196    async fn fetch_block_info(&self, hash: &str) -> Result<BlockInfo, WError> {
197        let url = format!("/blocks/{}", hash);
198
199        let resp = self
200            .maestro_client
201            .get(&url)
202            .await
203            .map_err(WError::from_err("maestro::fetch_block_info get"))?;
204        let m_block_info: MBlockInfo = serde_json::from_str(&resp)
205            .map_err(WError::from_err("maestro::fetch_block_info type error"))?;
206
207        let block_info: BlockInfo = block_info_data_to_block_info(m_block_info.data);
208
209        Ok(block_info)
210    }
211
212    async fn fetch_collection_assets(
213        &self,
214        policy_id: &str,
215        cursor: Option<String>,
216    ) -> Result<(Vec<(String, String)>, Option<String>), WError> {
217        let append_cursor_string = match cursor {
218            Some(c) => format!("&cursor={}", c),
219            None => "".to_string(),
220        };
221        let url = format!(
222            "/policy/{}/assets?count=100{}",
223            policy_id, append_cursor_string
224        );
225
226        let resp = self
227            .maestro_client
228            .get(&url)
229            .await
230            .map_err(WError::from_err("maestro::fetch_collection_assets get"))?;
231        let collection_assets: CollectionAssets = serde_json::from_str(&resp).map_err(
232            WError::from_err("maestro::fetch_collection_assets type error"),
233        )?;
234
235        let assets = collection_assets
236            .data
237            .iter()
238            .map(|asset_data| {
239                (
240                    format!("{}{}", policy_id, asset_data.asset_name.clone()),
241                    asset_data.total_supply.clone(),
242                )
243            })
244            .collect();
245
246        Ok((assets, collection_assets.next_cursor))
247    }
248
249    async fn fetch_protocol_parameters(&self, epoch: Option<u32>) -> Result<Protocol, WError> {
250        if let Some(_epoch) = epoch {
251            return Err(WError::new(
252                "",
253                "Maestro only supports fetching Protocol parameters of the latest completed epoch.",
254            ));
255        }
256
257        let protocol_url = "/protocol-parameters";
258
259        let protocol_resp = self
260            .maestro_client
261            .get(protocol_url)
262            .await
263            .map_err(WError::from_err("maestro::fetch_protocol_parameters get"))?;
264
265        let protocol_parameters: ProtocolParameters = serde_json::from_str(&protocol_resp)
266            .map_err(WError::from_err(
267                "maestro::fetch_protocol_parameters type error",
268            ))?;
269
270        let epoch_url = "/epochs/current";
271
272        let epoch_resp = self
273            .maestro_client
274            .get(epoch_url)
275            .await
276            .map_err(WError::from_err("maestro::fetch_current_epoch get"))?;
277
278        let epochs: EpochResp = serde_json::from_str(&epoch_resp)
279            .map_err(WError::from_err("maestro::fetch_current_epoch type error"))?;
280
281        let protocol: Protocol =
282            protocol_paras_data_to_protocol(protocol_parameters.data, epochs.data).map_err(
283                WError::from_err(
284                    "maestro::fetch_protocol_parameters protocol_paras_data_to_protocol",
285                ),
286            )?;
287        Ok(protocol)
288    }
289
290    async fn fetch_tx_info(&self, hash: &str) -> Result<TransactionInfo, WError> {
291        let url = format!("/transactions/{}", hash);
292
293        let resp = self
294            .maestro_client
295            .get(&url)
296            .await
297            .map_err(WError::from_err("maestro::fetch_tx_info get"))?;
298
299        let transaction_details: TransactionDetails = serde_json::from_str(&resp)
300            .map_err(WError::from_err("maestro::fetch_tx_info type error"))?;
301
302        let transaction_info: TransactionInfo =
303            transaction_detail_to_info(transaction_details.data).map_err(WError::from_err(
304                "maestro::fetch_tx_info transaction_detail_to_info",
305            ))?;
306        Ok(transaction_info)
307    }
308
309    async fn fetch_utxos(&self, hash: &str, index: Option<u32>) -> Result<Vec<UTxO>, WError> {
310        let url = format!("/transactions/{}", hash);
311
312        let resp = self
313            .maestro_client
314            .get(&url)
315            .await
316            .map_err(WError::from_err("maestro::fetch_utxos get"))?;
317
318        let transaction_details: TransactionDetails = serde_json::from_str(&resp)
319            .map_err(WError::from_err("maestro::fetch_utxos type error"))?;
320
321        let outputs: Vec<UTxO> = transaction_details
322            .data
323            .outputs
324            .iter()
325            .map(to_utxo)
326            .collect::<Result<Vec<UTxO>, _>>()
327            .map_err(WError::from_err("maestro::fetch_utxos  - to_utxo"))?;
328
329        let utxos = match index {
330            Some(i) => outputs
331                .iter()
332                .filter(|output| output.input.output_index == i)
333                .cloned()
334                .collect(),
335            None => outputs,
336        };
337
338        Ok(utxos)
339    }
340
341    async fn get(&self, url: &str) -> Result<serde_json::Value, WError> {
342        let resp = self
343            .maestro_client
344            .get(url)
345            .await
346            .map_err(WError::from_err("maestro::get"))?;
347        let any = serde_json::from_str(&resp).map_err(WError::from_err("maestro::get"))?;
348        Ok(any)
349    }
350}