esplora_api/async_impl/
client.rs

1use std::collections::HashMap;
2use reqwest;
3
4use crate::data::blockstream::{
5    AddressInfoFormat, BlockFormat, BlockStatus, MemPoolFormat, MempoolTxFormat, MerkleProofFormat,
6    OutspentFormat, TransactionFormat, TxStatusFormat, UtxoFormat,
7};
8
9/// Client to call esplora api, it use and Esplora Api Url. I can use custom reqwest Client build from reqwest client builder
10#[derive(Debug)]
11pub struct ApiClient {
12    pub url: String,
13    pub reqwest: reqwest::Client,
14}
15/// Client basics options used to custom reqwest client
16#[derive(Debug)]
17pub struct ClientOptions {
18    pub headers: Option<HeadersOptions>,
19}
20/// Headers options can be used to use authorization header
21#[derive(Debug)]
22pub struct HeadersOptions {
23    pub authorization: Option<String>,
24}
25
26impl ApiClient {
27    /// new client from endpoint Esplora Api Url, and ClientOptions.
28    /// 
29    /// Example without options :
30    /// ````rust
31    /// use esplora_api::async_impl::ApiClient;
32    /// 
33    /// fn main(){
34    ///     let client = esplora_api::async_impl::ApiClient::new("https://some_esplora_url.com", None);
35    /// }
36    /// ````
37    /// Example with custom authorization header :
38    /// ````rust
39    /// use esplora_api::async_impl::{ApiClient, ClientOptions, HeadersOptions};
40    /// 
41    /// fn main(){
42    ///     let options = ClientOptions { headers: Some( HeadersOptions { authorization: Some("secret".to_string())}),};
43    ///     let client = esplora_api::async_impl::ApiClient::new("https://some_esplora_url.com", Some(options));
44    /// }
45    /// ````
46    pub fn new(
47        url: &str,
48        options: Option<ClientOptions>,
49    ) -> Result<Self, Box<dyn std::error::Error>> {
50        let mut client_builder = reqwest::ClientBuilder::new();
51        // Find options
52        match options {
53            // Build headers
54            Some(ClientOptions { headers, .. }) => {
55                let mut headers_map = reqwest::header::HeaderMap::new();
56                match headers {
57                    // header::AUTHORIZATION
58                    Some(HeadersOptions {
59                        authorization: Some(authorization),
60                    }) => {
61                        headers_map.insert(
62                            reqwest::header::AUTHORIZATION,
63                            reqwest::header::HeaderValue::from_str(&authorization).unwrap(),
64                        );
65                    }
66                    _ => (),
67                }
68                client_builder = client_builder.default_headers(headers_map);
69            }
70            None => (),
71        }
72        let build = client_builder.build().unwrap_or(reqwest::Client::new());
73
74        Ok(ApiClient {
75            url: url.to_string(),
76            reqwest: build,
77        })
78    }
79    /// new_from_config new client from endpoint Esplora Api Url, and reqwest client.
80    /// 
81    /// Example without custom reqwest client :
82    /// ````rust
83    /// use esplora_api::async_impl::ApiClient;
84    /// use reqwest;
85    /// use reqwest::header;
86    /// fn main(){
87    ///     let mut headers = header::HeaderMap::new();
88    ///     headers.insert(header::AUTHORIZATION,header::HeaderValue::from_static("secret"));
89    ///     let reqwest_client = reqwest::Client::builder().default_headers(headers).build().unwrap();
90    ///     let client = esplora_api::async_impl::ApiClient::new_from_config("https://some_esplora_url.com", reqwest_client);
91    /// }
92    /// ````
93    pub fn new_from_config(
94        url: &str,
95        client: reqwest::Client
96    )->Result<Self, Box<dyn std::error::Error>> {
97        Ok(ApiClient {
98            url: url.to_string(),
99            reqwest: client,
100        })
101    }
102    /// get_block Returns information about a block.
103    ///
104    /// Route : GET /block/:hash. Available fields:
105    ///
106    /// Elements-based chains have an additional proof field. See block format for more details.
107    /// The response from this endpoint can be cached indefinitely.
108    ///
109    /// Example :
110    /// ````rust
111    /// use esplora_api;
112    ///
113    /// #[tokio::main]
114    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
115    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
116    ///     let response = client.get_block("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7").await?;
117    ///     println!("{:?}",response);
118    ///     Ok(())
119    /// }
120    /// ````
121    pub async fn get_block(&self, hash: &str) -> Result<BlockFormat, Box<dyn std::error::Error>> {
122        let request_url = format!("{}/block/{}", self.url, hash);
123        let resp: BlockFormat = self.reqwest.get(&request_url).send().await?.json().await?;
124        Ok(resp)
125    }
126    /// get_block_status Returns the block status.
127    ///
128    /// Route : GET /block/:hash/status. Available fields:
129    ///
130    /// Example :
131    /// ````rust
132    /// use esplora_api;
133    ///
134    /// #[tokio::main]
135    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
136    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
137    ///     let response = client.get_block_status("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7").await?;
138    ///     println!("{:?}",response);
139    ///     Ok(())
140    /// }
141    /// ````
142    pub async fn get_block_status(
143        &self,
144        hash: &str,
145    ) -> Result<BlockStatus, Box<dyn std::error::Error>> {
146        let request_url = format!("{}{}{}{}", self.url, "/block/", hash, "/status");
147        let resp: BlockStatus = self.reqwest.get(&request_url).send().await?.json().await?;
148        Ok(resp)
149    }
150    /// get_block_txs Returns a list of transactions in the block (up to 25 transactions beginning at start_index).
151    ///
152    /// Route : GET /block/:hash/txs[/:start_index]
153    ///
154    /// Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.
155    /// The response from this endpoint can be cached indefinitely.
156    ///
157    /// Example :
158    /// ````rust
159    /// use esplora_api;
160    ///
161    /// #[tokio::main]
162    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
163    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
164    ///     let response = client.get_block_txs("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7", Some(25)).await?;
165    ///     println!("{:?}",response);
166    ///     Ok(())
167    /// }
168    /// ````
169    pub async fn get_block_txs(
170        &self,
171        hash: &str,
172        start_index: Option<i32>, // Why Option ?
173    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
174        let request_url = if let Some(i) = start_index {
175            format!("{}/block/{}/txs/{}", self.url, hash, i)
176        } else {
177            format!("{}/block/{}/txs", self.url, hash)
178        };
179        let resp: Vec<TransactionFormat> =
180            self.reqwest.get(&request_url).send().await?.json().await?;
181        Ok(resp)
182    }
183    /// get_block_txids Returns a list of all txids in the block.
184    ///
185    /// Route : GET /block/:hash/txids
186    ///
187    ///The response from this endpoint can be cached indefinitely.
188    ///
189    /// Example :
190    /// ````rust
191    /// use esplora_api;
192    ///
193    /// #[tokio::main]
194    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
195    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
196    ///     let response = client.get_block_txids("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7").await?;
197    ///     println!("{:?}",response);
198    ///     Ok(())
199    /// }
200    /// ````
201    pub async fn get_block_txids(
202        &self,
203        hash: &str,
204    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
205        let request_url = format!("{}{}{}{}", self.url, "/block/", hash, "/txids");
206        let resp: Vec<String> = self.reqwest.get(&request_url).send().await?.json().await?;
207        Ok(resp)
208    }
209    /// get_block_txid_at_index Returns the transaction at index :index within the specified block.
210    ///
211    /// Route : GET /block/:hash/txid/:index
212    ///
213    /// The response from this endpoint can be cached indefinitely.
214    ///
215    /// Example :
216    /// ````rust
217    /// use esplora_api;
218    ///
219    /// #[tokio::main]
220    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
221    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
222    ///     let response = client.get_block_txid_at_index("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7",25).await?;
223    ///     println!("{:?}",response);
224    ///     Ok(())
225    /// }
226    /// ````
227    pub async fn get_block_txid_at_index(
228        &self,
229        hash: &str,
230        index: i32,
231    ) -> Result<String, Box<dyn std::error::Error>> {
232        let request_url = format!("{}/block/{}/txid/{}", self.url, hash, index);
233        let resp: String = self.reqwest.get(&request_url).send().await?.text().await?;
234        Ok(resp)
235    }
236    /// get_block_raw_format Returns the raw block representation in binary.
237    ///
238    /// Route : GET /block/:hash/raw
239    ///
240    /// The response from this endpoint can be cached indefinitely.
241    ///
242    /// Example :
243    /// ````rust
244    /// use esplora_api;
245    ///
246    /// #[tokio::main]
247    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
248    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
249    ///     let response = client.get_block_raw_format("000000000000003aaa3b99e31ed1cac4744b423f9e52ada4971461c81d4192f7").await?;
250    ///     println!("{:?}",response);
251    ///     Ok(())
252    /// }
253    /// ````
254
255    pub async fn get_block_raw_format(
256        &self,
257        hash: &str,
258    ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
259        let request_url = format!("{}/block/{}/raw", self.url, hash);
260        let resp = self
261            .reqwest
262            .get(&request_url)
263            .send()
264            .await?
265            .bytes()
266            .await?
267            .to_vec();
268        Ok(resp)
269    }
270
271    /// get_block_height Returns the hash of the block currently at height.
272    ///
273    /// Route : GET /block-height/:height
274    ///
275    /// Example :
276    /// ````rust
277    /// use esplora_api;
278    ///
279    /// #[tokio::main]
280    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
281    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
282    ///     let response = client.get_block_height(424242).await?;
283    ///     println!("{:?}",response);
284    ///     Ok(())
285    /// }
286    /// ````
287    pub async fn get_block_height(
288        &self,
289        height: i32,
290    ) -> Result<String, Box<dyn std::error::Error>> {
291        let request_url = format!("{}/block-height/{}", self.url, height);
292        let resp = self.reqwest.get(&request_url).send().await?.text().await?;
293        Ok(resp)
294    }
295    /// get_blocks Returns the 10 newest blocks starting at the tip or at start_height if specified.
296    ///
297    /// Route : GET /blocks[/:start_height]
298    ///
299    /// Example :
300    /// ````rust
301    /// use esplora_api;
302    ///
303    /// #[tokio::main]
304    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
305    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
306    ///     let response = client.get_blocks(1234).await?;
307    ///     println!("{:?}",response);
308    ///     Ok(())
309    /// }
310    /// ````
311
312    pub async fn get_blocks(
313        &self,
314        start_height: i32,
315    ) -> Result<Vec<BlockFormat>, Box<dyn std::error::Error>> {
316        let request_url = format!("{}/blocks/{}", self.url, start_height);
317        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
318        Ok(resp)
319    }
320    /// get_blocks_tip_height Returns the height of the last block.
321    ///
322    /// Route : GET /blocks/tip/height
323    ///
324    /// Example :
325    /// ````rust
326    /// use esplora_api;
327    ///
328    /// #[tokio::main]
329    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
330    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
331    ///     let response = client.get_blocks_tip_height().await?;
332    ///     println!("{:?}",response);
333    ///     Ok(())
334    /// }
335    /// ````
336
337    pub async fn get_blocks_tip_height(&self) -> Result<i32, Box<dyn std::error::Error>> {
338        let request_url = format!("{}/blocks/tip/height", self.url);
339        let resp = self
340            .reqwest
341            .get(&request_url)
342            .send()
343            .await?
344            .text()
345            .await?
346            .parse()?;
347        Ok(resp)
348    }
349    /// get_blocks_tip_hash Returns the hash of the last block.
350    ///
351    /// Route : GET /blocks/tip/hash
352    ///
353    ///
354    ///
355    /// Example :
356    /// ````rust
357    /// use esplora_api;
358    ///
359    /// #[tokio::main]
360    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
361    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
362    ///     let response = client.get_blocks_tip_height().await?;
363    ///     println!("{:?}",response);
364    ///     Ok(())
365    /// }
366    /// ````
367
368    pub async fn get_blocks_tip_hash(&self) -> Result<String, Box<dyn std::error::Error>> {
369        let request_url = format!("{}/blocks/tip/hash", self.url);
370        let resp = self.reqwest.get(&request_url).send().await?.text().await?;
371        Ok(resp)
372    }
373    /// get_tx Returns information about the transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout and status (see transaction format for details).
374    ///
375    /// Route : GET /tx/:txid
376    ///
377    /// Example :
378    /// ````rust
379    /// use esplora_api;
380    ///
381    /// #[tokio::main]
382    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
383    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
384    ///     let response = client.get_tx("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
385    ///     println!("{:?}",response);
386    ///     Ok(())
387    /// }
388    /// ````
389
390    pub async fn get_tx(
391        &self,
392        txid: &str,
393    ) -> Result<TransactionFormat, Box<dyn std::error::Error>> {
394        let request_url = format!("{}/tx/{}", self.url, txid);
395        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
396        Ok(resp)
397    }
398    /// get_tx_status Returns the transaction confirmation status. Available fields: confirmed (boolean), block_height (optional) and block_hash (optional).
399    ///
400    /// Route : GET /tx/:txid/status
401    ///
402    /// Example :
403    /// ````rust
404    /// use esplora_api;
405    ///
406    /// #[tokio::main]
407    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
408    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
409    ///     let response = client.get_tx_status("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
410    ///     println!("{:?}",response);
411    ///     Ok(())
412    /// }
413    /// ````
414    pub async fn get_tx_status(
415        &self,
416        txid: &str,
417    ) -> Result<TxStatusFormat, Box<dyn std::error::Error>> {
418        let request_url = format!("{}/tx/{}/status", self.url, txid);
419        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
420        Ok(resp)
421    }
422
423    /// get_tx_raw Returns the raw transaction as binary data.
424    ///
425    /// Route : GET /tx/:txid/raw
426    ///
427    /// Example :
428    /// ````rust
429    /// use esplora_api;
430    ///
431    /// #[tokio::main]
432    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
433    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
434    ///     let response = client.get_tx_raw("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
435    ///     println!("{:?}",response);
436    ///     Ok(())
437    /// }
438    /// ````
439    pub async fn get_tx_raw(&self, txid: &str) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
440        let request_url = format!("{}/tx/{}/raw", self.url, txid);
441        let resp = self
442            .reqwest
443            .get(&request_url)
444            .send()
445            .await?
446            .bytes()
447            .await?
448            .to_vec();
449        Ok(resp)
450    }
451
452    /// get_tx_hex Returns the raw transaction in hex
453    ///
454    /// Route : GET /tx/:txid/hex
455    ///
456    /// Example :
457    /// ````rust
458    /// use esplora_api;
459    ///
460    /// #[tokio::main]
461    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
462    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
463    ///     let response = client.get_tx_hex("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
464    ///     println!("{:?}",response);
465    ///     Ok(())
466    /// }
467    /// ````
468    pub async fn get_tx_hex(&self, txid: &str) -> Result<String, Box<dyn std::error::Error>> {
469        let request_url = format!("{}/tx/{}/raw", self.url, txid);
470        let resp = self.reqwest.get(&request_url).send().await?.text().await?;
471        Ok(resp)
472    }
473    /// get_tx_merkleblock_proof Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format.
474    /// Note: This endpoint is not currently available for Liquid/Elements-based chains.
475    /// Route : GET /tx/:txid/merkleblock-proof
476    ///
477    /// Example :
478    /// ````rust
479    /// use esplora_api;
480    ///
481    /// #[tokio::main]
482    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
483    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
484    ///     let response = client.get_tx_merkleblock_proof("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
485    ///     println!("{:?}",response);
486    ///     Ok(())
487    /// }
488    /// ````
489    pub async fn get_tx_merkleblock_proof(
490        &self,
491        txid: &str,
492    ) -> Result<String, Box<dyn std::error::Error>> {
493        let request_url = format!("{}/tx/{}/merkleblock-proof", self.url, txid);
494        let resp = self.reqwest.get(&request_url).send().await?.text().await?;
495        Ok(resp)
496    }
497
498    /// get_tx_merkle_proof Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format.
499    ///
500    /// Route : GET /tx/:txid/merkle-proof
501    ///
502    /// Example :
503    /// ````rust
504    /// use esplora_api;
505    ///
506    /// #[tokio::main]
507    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
508    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
509    ///     let response = client.get_tx_merkle_proof("c9ee6eff3d73d6cb92382125c3207f6447922b545d4d4e74c47bfeb56fff7d24").await?;
510    ///     println!("{:?}",response);
511    ///     Ok(())
512    /// }
513    /// ````
514    pub async fn get_tx_merkle_proof(
515        &self,
516        txid: &str,
517    ) -> Result<MerkleProofFormat, Box<dyn std::error::Error>> {
518        let request_url = format!("{}/tx/{}/merkle-proof", self.url, txid);
519        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
520        Ok(resp)
521    }
522
523    /// get_tx_outspend Returns the spending status of a transaction output.
524    /// Available fields: spent (boolean), txid (optional), vin (optional) and status (optional, the status of the spending tx).
525    ///
526    /// Route : GET /tx/:txid/outspend/:vout
527    ///
528    /// Example :
529    /// ````rust
530    /// use esplora_api;
531    ///
532    /// #[tokio::main]
533    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
534    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
535    ///     let response = client.get_tx_outspend("fac9af7f793330af3cc0bce4790d98499c59d47a125af7260edd61d647003316",Some(1)).await?;
536    ///     println!("{:?}",response);
537    ///     Ok(())
538    /// }
539    /// ````
540    pub async fn get_tx_outspend(
541        &self,
542        txid: &str,
543        vout: Option<i32>,
544    ) -> Result<OutspentFormat, Box<dyn std::error::Error>> {
545        let request_url = if let Some(vout_idx) = vout {
546            format!("{}/tx/{}/outspend/{}", self.url, txid, vout_idx)
547        } else {
548            format!("{}/tx/{}/outspend", self.url, txid) // FIXME: not sure if this exist
549        };
550        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
551        Ok(resp)
552    }
553
554    /// get_tx_outspends Returns the spending status of all transaction outputs.
555    ///
556    /// Route : GET /tx/:txid/outspends
557    ///
558    /// Example :
559    /// ````rust
560    /// use esplora_api;
561    ///
562    /// #[tokio::main]
563    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
564    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
565    ///     let response = client.get_tx_outspends("fac9af7f793330af3cc0bce4790d98499c59d47a125af7260edd61d647003316").await?;
566    ///     println!("{:?}",response);
567    ///     Ok(())
568    /// }
569    /// ````
570
571    pub async fn get_tx_outspends(
572        &self,
573        txid: &str,
574    ) -> Result<Vec<OutspentFormat>, Box<dyn std::error::Error>> {
575        let request_url = format!("{}/tx/{}/outspends", self.url, txid);
576        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
577        Ok(resp)
578    }
579
580    /// post_tx Broadcast a raw transaction to the network.
581    /// The transaction should be provided as hex in the request body. The txid will be returned on success.
582    ///
583    /// Route : POST /tx
584    ///
585    pub async fn post_tx(
586        &self,
587        hex_transaction: &str,
588    ) -> Result<String, Box<dyn std::error::Error>> {
589        let request_url = format!("{}/tx", self.url);
590        let resp = self
591            .reqwest
592            .post(&request_url)
593            .body(hex_transaction.to_string())
594            .send()
595            .await?
596            .text()
597            .await?;
598        Ok(resp)
599    }
600
601    /// get_address Get information about an address
602    /// Available fields: address/scripthash, chain_stats and mempool_stats.
603    /// {chain,mempool}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count and spent_txo_sum.
604    /// Elements-based chains don't have the {funded,spent}_txo_sum fields.
605    ///
606    /// Route : GET /address/:address
607    ///
608    /// Example :
609    /// ````rust
610    /// use esplora_api;
611    ///
612    /// #[tokio::main]
613    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
614    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
615    ///     let response = client.get_address("2MvJVm11phGoxEekPB8Hw2Tksb57eVRGHC5").await?;
616    ///     println!("{:?}",response);
617    ///     Ok(())
618    /// }
619    /// ````
620    pub async fn get_address(
621        &self,
622        address: &str,
623    ) -> Result<AddressInfoFormat, Box<dyn std::error::Error>> {
624        let request_url = format!("{}/address/{}", self.url, address);
625        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
626        Ok(resp)
627    }
628
629    /// get_script_hash Get information about an scripthash
630    /// Available fields: scripthash, chain_stats and mempool_stats.
631    /// {chain,mempool}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count and spent_txo_sum.
632    /// Elements-based chains don't have the {funded,spent}_txo_sum fields.
633    ///
634    /// Route : GET /scripthash/:hash
635    ///
636    /// Example :
637    /// ````rust
638    /// use esplora_api;
639    ///
640    /// #[tokio::main]
641    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
642    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
643    ///     let response = client.get_script_hash("c6598a8e5728c744b9734facbf1e786c3ff5101268739d38b14ea475b60eba3c").await?;
644    ///     println!("{:?}",response);
645    ///     Ok(())
646    /// }
647    /// ````
648    pub async fn get_script_hash(
649        &self,
650        scripthash: &str,
651    ) -> Result<AddressInfoFormat, Box<dyn std::error::Error>> {
652        let request_url = format!("{}/scripthash/{}", self.url, scripthash);
653        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
654        Ok(resp)
655    }
656
657    /// get_address_txs Get transaction history for the specified address/scripthash, sorted with newest first.
658    /// Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid(see below).
659    ///
660    /// Route : GET /address/:address/txs
661    ///
662    /// Example :
663    /// ````rust
664    /// use esplora_api;
665    ///
666    /// #[tokio::main]
667    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
668    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
669    ///     let response = client.get_address_txs("2MvJVm11phGoxEekPB8Hw2Tksb57eVRGHC5").await?;
670    ///     println!("{:?}",response);
671    ///     Ok(())
672    /// }
673    /// ````
674    pub async fn get_address_txs(
675        &self,
676        address: &str,
677    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
678        let request_url = format!("{}/address/{}/txs", self.url, address);
679        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
680        Ok(resp)
681    }
682    /// get_script_hash_txs Get transaction history for the specified address/scripthash, sorted with newest first.
683    /// Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid(see below).
684    ///
685    /// Route : GET /scripthash/:hash/txs
686    ///
687    /// Example :
688    /// ````rust
689    /// use esplora_api;
690    ///
691    /// #[tokio::main]
692    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
693    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
694    ///     let response = client.get_script_hash_txs("c6598a8e5728c744b9734facbf1e786c3ff5101268739d38b14ea475b60eba3c").await?;
695    ///     println!("{:?}",response);
696    ///     Ok(())
697    /// }
698    /// ````
699
700    pub async fn get_script_hash_txs(
701        &self,
702        scripthash: &str,
703    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
704        let request_url = format!("{}/scripthash/{}/txs", self.url, scripthash);
705        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
706        Ok(resp)
707    }
708
709    /// get_address_txs_chain Get confirmed transaction history for the specified address/scripthash, sorted with newest first.
710    /// Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.
711    ///
712    /// Route : GET /address/:address/txs/chain[/:last_seen_txid]
713    ///
714    /// Example :
715    /// ````rust
716    /// use esplora_api;
717    ///
718    /// #[tokio::main]
719    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
720    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
721    ///     let response = client.get_address_txs_chain("n1vgV8XmoggmRXzW3hGD8ZNTAgvhcwT4Gk",Some("d0075b62f8b3e464472b8edecf56083ca3e9e8424f5f332ed2f9045d7fcccddc")).await?;
722    ///     println!("{:?}",response);
723    ///     Ok(())
724    /// }
725    /// ````
726    pub async fn get_address_txs_chain(
727        &self,
728        address: &str,
729        txid: Option<&str>,
730    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
731        let request_url = if let Some(id) = txid {
732            format!("{}/address/{}/txs/chain/{}", self.url, address, id)
733        } else {
734            format!("{}/address/{}/txs/chain", self.url, address)
735        };
736        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
737        Ok(resp)
738    }
739
740    /// get_script_hash_txs_chain Get confirmed transaction history for the specified address/scripthash, sorted with newest first.
741    /// Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.
742    ///
743    /// Route : GET /scripthash/:hash/txs/chain[/:last_seen_txid]
744    ///
745    /// Example :
746    /// ````rust
747    /// use esplora_api;
748    ///
749    /// #[tokio::main]
750    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
751    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
752    ///     let response = client.get_script_hash_txs_chain("c6598a8e5728c744b9734facbf1e786c3ff5101268739d38b14ea475b60eba3c",None).await?;
753    ///     println!("{:?}",response);
754    ///     Ok(())
755    /// }
756    /// ````
757    pub async fn get_script_hash_txs_chain(
758        &self,
759        scripthash: &str,
760        txid: Option<&str>,
761    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
762        let request_url = if let Some(id) = txid {
763            format!("{}/scripthash/{}/txs/chain/{}", self.url, scripthash, id)
764        } else {
765            format!("{}/scripthash/{}/txs/chain", self.url, scripthash)
766        };
767        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
768        Ok(resp)
769    }
770
771    /// get_address_txs_mempool Get unconfirmed transaction history for the specified address.
772    /// Returns up to 50 transactions (no paging).
773    ///
774    /// Route : GET /address/:address/txs/mempool
775    ///
776    /// Example :
777    /// ````rust
778    /// use esplora_api;
779    ///
780    /// #[tokio::main]
781    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
782    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
783    ///     let response = client.get_address_txs_mempool("2MvJVm11phGoxEekPB8Hw2Tksb57eVRGHC5").await?;
784    ///     println!("{:?}",response);
785    ///     Ok(())
786    /// }
787    /// ````
788    pub async fn get_address_txs_mempool(
789        &self,
790        address: &str,
791    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
792        let request_url = format!("{}/address/{}/txs/mempool", self.url, address);
793        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
794        Ok(resp)
795    }
796
797    /// get_script_hash_txs_mempool Get unconfirmed transaction history for the specified scripthash.
798    /// Returns up to 50 transactions (no paging).
799    ///
800    /// Route : GET /scripthash/:hash/txs/mempool
801    ///
802    /// Example :
803    /// ````rust
804    /// use esplora_api;
805    ///
806    /// #[tokio::main]
807    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
808    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
809    ///     let response = client.get_script_hash_txs_mempool("c6598a8e5728c744b9734facbf1e786c3ff5101268739d38b14ea475b60eba3c").await?;
810    ///     println!("{:?}",response);
811    ///     Ok(())
812    /// }
813    /// ````
814    pub async fn get_script_hash_txs_mempool(
815        &self,
816        scripthash: &str,
817    ) -> Result<Vec<TransactionFormat>, Box<dyn std::error::Error>> {
818        let request_url = format!("{}/scripthash/{}/txs/mempool", self.url, scripthash,);
819        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
820        Ok(resp)
821    }
822
823    /// get_address_utxo Get the list of unspent transaction outputs associated with the address
824    /// Available fields: txid, vout, value and status (with the status of the funding tx).
825    /// Elements-based chains have a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof and range_proof.
826    ///
827    /// Route : GET /address/:address/utxo
828    ///
829    /// Example :
830    /// ````rust
831    /// use esplora_api;
832    ///
833    /// #[tokio::main]
834    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
835    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
836    ///     let response = client.get_address_utxo("2NDcM3CGUTwqFL7y8BSBJTYJ9kToeXawkUF").await?;
837    ///     println!("{:?}",response);
838    ///     Ok(())
839    /// }
840    /// ````
841    pub async fn get_address_utxo(
842        &self,
843        address: &str,
844    ) -> Result<Vec<UtxoFormat>, Box<dyn std::error::Error>> {
845        let request_url = format!("{}/address/{}/utxo", self.url, address);
846        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
847        Ok(resp)
848    }
849
850    /// get_script_hash_utxo Get the list of unspent transaction outputs associated with the address
851    /// Available fields: txid, vout, value and status (with the status of the funding tx).
852    /// Elements-based chains have a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof and range_proof.
853    ///
854    /// Route : GET /scripthash/:hash/utxo
855    ///
856    /// Example :
857    /// ````rust
858    /// use esplora_api;
859    ///
860    /// #[tokio::main]
861    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
862    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
863    ///     let response = client.get_script_hash_utxo("c6598a8e5728c744b9734facbf1e786c3ff5101268739d38b14ea475b60eba3c").await?;
864    ///     println!("{:?}",response);
865    ///     Ok(())
866    /// }
867    /// ````
868    pub async fn get_script_hash_utxo(
869        &self,
870        scripthash: &str,
871    ) -> Result<Vec<UtxoFormat>, Box<dyn std::error::Error>> {
872        let request_url = format!("{}/scripthash/{}/utxo", self.url, scripthash);
873        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
874        Ok(resp)
875    }
876    /// get_address_prefix  This feature is disabled by default on custom api Search for addresses beginning with :prefix.
877    /// Returns a JSON array with up to 10 results.
878    ///
879    /// Route : GET /address-prefix/:prefix
880    ///
881    /// Example :
882    /// ````rust
883    /// use esplora_api;
884    ///
885    /// #[tokio::main]
886    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
887    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
888    ///     let response = client.get_address_prefix("2NDcM").await?;
889    ///     println!("{:?}",response);
890    ///     Ok(())
891    /// }
892    /// ````
893
894    pub async fn get_address_prefix(
895        &self,
896        prefix: &str,
897    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
898        let request_url = format!("{}/address-prefix/{}", self.url, prefix);
899        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
900        Ok(resp)
901    }
902    /// get_mempool Get mempool backlog statistics. Returns an object with:
903    ///     count: the number of transactions in the mempool
904    ///     vsize: the total size of mempool transactions in virtual bytes
905    ///     total_fee: the total fee paid by mempool transactions in satoshis
906    ///     fee_histogram: mempool fee-rate distribution histogram
907    ///     An array of (feerate, vsize) tuples, where each entry's vsize is the total vsize of transactions paying more than feerate but less than the previous entry's feerate (except for the first entry, which has no upper bound). This matches the format used by the Electrum RPC protocol for mempool.get_fee_histogram.
908    ///
909    /// Route : GET /mempool
910    ///
911    /// Example :
912    /// ````rust
913    /// use esplora_api;
914    ///
915    /// #[tokio::main]
916    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
917    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
918    ///     let response = client.get_mempool().await?;
919    ///     println!("{:?}",response);
920    ///     Ok(())
921    /// }
922    /// ````
923    /// Example output:
924    /// ````json
925    /// {
926    ///   "count": 8134,
927    ///   "vsize": 3444604,
928    ///   "total_fee":29204625,
929    ///   "fee_histogram": [[53.01, 102131], [38.56, 110990], [34.12, 138976], [24.34, 112619], [3.16, 246346], [2.92, 239701], [1.1, 775272]]
930    /// }
931    /// ````
932    /// In this example, there are transactions weighting a total of 102,131 vbytes that are paying more than 53 sat/vB, 110,990 vbytes of transactions paying between 38 and 53 sat/vB, 138,976 vbytes paying between 34 and 38, etc.
933    pub async fn get_mempool(&self) -> Result<MemPoolFormat, Box<dyn std::error::Error>> {
934        let request_url = format!("{}/mempool", self.url);
935        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
936        Ok(resp)
937    }
938    /// get_mempool_txids Get the full list of txids in the mempool as an array.
939    /// The order of the txids is arbitrary and does not match bitcoind's.
940    ///
941    /// Route : GET /mempool/txids
942    ///
943    /// Example :
944    /// ````rust
945    /// use esplora_api;
946    ///
947    /// #[tokio::main]
948    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
949    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
950    ///     let response = client.get_mempool_txids().await?;
951    ///     println!("{:?}",response);
952    ///     Ok(())
953    /// }
954    /// ````
955    pub async fn get_mempool_txids(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
956        let request_url = format!("{}/mempool/txids", self.url);
957        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
958        Ok(resp)
959    }
960    /// get_mempool_recent  Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize and value
961    /// Fee estimates
962    /// The order of the txids is arbitrary and does not match bitcoind's.
963    ///
964    /// Route : GET /mempool/recent
965    ///
966    /// Example :
967    /// ````rust
968    /// use esplora_api;
969    ///
970    /// #[tokio::main]
971    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
972    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
973    ///     let response = client.get_mempool_recent().await?;
974    ///     println!("{:?}",response);
975    ///     Ok(())
976    /// }
977    /// ````
978
979    pub async fn get_mempool_recent(
980        &self,
981    ) -> Result<Vec<MempoolTxFormat>, Box<dyn std::error::Error>> {
982        let request_url = format!("{}/mempool/recent", self.url);
983        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
984        Ok(resp)
985    }
986    /// fee_estimate Get an object where the key is the confirmation target (in number of blocks) and the value is the estimated feerate (in sat/vB).
987    /// The available confirmation targets are 1-25, 144, 504 and 1008 blocks.
988    /// For example: { "1": 87.882, "2": 87.882, "3": 87.882, "4": 87.882, "5": 81.129, "6": 68.285, ..., "144": 1.027, "504": 1.027, "1008": 1.027 }
989    ///
990    /// Route : GET /fee-estimates
991    ///
992    /// Example :
993    /// ````rust
994    /// use esplora_api;
995    ///
996    /// #[tokio::main]
997    /// async fn run() -> Result<(), Box<dyn std::error::Error>> {
998    ///     let client = esplora_api::async_impl::ApiClient::new("https://blockstream.info/testnet/api/", None).unwrap();
999    ///     let response = client.fee_estimate().await?;
1000    ///     println!("{:?}",response);
1001    ///     Ok(())
1002    /// }
1003    /// ````
1004
1005    pub async fn fee_estimate(&self) -> Result<HashMap<String, f32>, Box<dyn std::error::Error>> {
1006        let request_url = format!("{}/fee-estimates", self.url);
1007        let resp = self.reqwest.get(&request_url).send().await?.json().await?;
1008        Ok(resp)
1009    }
1010}