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}