koios_sdk/api/
asset.rs

1use crate::{
2    error::Result,
3    models::{
4        asset::{AssetHistory, AssetInfo, AssetList, AssetTokenRegistry, PolicyAssetList},
5        requests::{AssetListRequest, AssetListWithExtendedRequest},
6        AddressTransaction, AssetNftAddress, AssetSummary, PolicyAssetAddresses, PolicyAssetInfo,
7        PolicyAssetMint, UtxoInfo,
8    },
9    types::{AfterBlockHeight, AssetName, AssetNameNft, AssetPolicy, AssetPolicyNft},
10    Client,
11};
12use urlencoding::encode;
13
14impl Client {
15    /// Get the list of all native assets (paginated)
16    ///
17    /// # Examples
18    ///
19    /// ```no_run
20    /// use koios_sdk::Client;
21    ///
22    /// #[tokio::main]
23    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
24    ///     let client = Client::new()?;
25    ///     let assets = client.get_asset_list().await?;
26    ///     println!("Asset list: {:?}", assets);
27    ///     Ok(())
28    /// }
29    /// ```
30    pub async fn get_asset_list(&self) -> Result<Vec<AssetList>> {
31        self.get("/asset_list").await
32    }
33
34    /// Get the list of assets under the given policy (including balances)
35    ///
36    /// # Arguments
37    ///
38    /// * `policy_id` - Policy ID to query
39    ///
40    /// # Examples
41    ///
42    /// ```no_run
43    /// use koios_sdk::Client;
44    /// use koios_sdk::types::AssetPolicy;
45    ///
46    /// #[tokio::main]
47    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
48    ///     let client = Client::new()?;
49    ///     let policy_id = AssetPolicy::new(
50    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
51    ///     );
52    ///     let assets = client.get_policy_asset_list(&policy_id).await?;
53    ///     println!("Policy assets: {:?}", assets);
54    ///     Ok(())
55    /// }
56    /// ```
57    pub async fn get_policy_asset_list(
58        &self,
59        policy_id: &AssetPolicy,
60    ) -> Result<Vec<PolicyAssetList>> {
61        self.get(&format!(
62            "/policy_asset_list?_asset_policy={}",
63            encode(policy_id.value())
64        ))
65        .await
66    }
67
68    /// Get a list of assets registered via token registry on github
69    ///
70    /// # Examples
71    ///
72    /// ```no_run
73    /// use koios_sdk::Client;
74    ///
75    /// #[tokio::main]
76    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
77    ///     let client = Client::new()?;
78    ///     let registry = client.get_asset_token_registry().await?;
79    ///     println!("Token registry: {:?}", registry);
80    ///     Ok(())
81    /// }
82    /// ```
83    pub async fn get_asset_token_registry(&self) -> Result<Vec<AssetTokenRegistry>> {
84        self.get("/asset_token_registry").await
85    }
86
87    /// Get the information of a list of assets including first minting & token registry metadata
88    ///
89    /// # Arguments
90    ///
91    /// * `asset_list` - List of asset pairs (policy_id, asset_name) to query
92    ///
93    /// # Examples
94    ///
95    /// ```no_run
96    /// use koios_sdk::Client;
97    ///
98    /// #[tokio::main]
99    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
100    ///     let client = Client::new()?;
101    ///     let asset_list = vec![
102    ///         vec![
103    ///             "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209".to_string(),
104    ///             "token1".to_string()
105    ///         ]
106    ///     ];
107    ///     let asset_info = client.get_asset_info(&asset_list).await?;
108    ///     println!("Asset info: {:?}", asset_info);
109    ///     Ok(())
110    /// }
111    /// ```
112    pub async fn get_asset_info(&self, asset_list: &[Vec<String>]) -> Result<Vec<AssetInfo>> {
113        let request = AssetListRequest::new(asset_list.to_vec());
114        self.post("/asset_info", &request).await
115    }
116
117    /// Get the UTXO information of a list of assets
118    ///
119    /// # Arguments
120    ///
121    /// * `asset_list` - List of asset pairs (policy_id, asset_name) to query
122    /// * `extended` - Optional flag to include extended information
123    ///
124    /// # Examples
125    ///
126    /// ```no_run
127    /// use koios_sdk::Client;
128    ///
129    /// #[tokio::main]
130    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
131    ///     let client = Client::new()?;
132    ///     let asset_list = vec![
133    ///         vec![
134    ///             "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209".to_string(),
135    ///             "token1".to_string()
136    ///         ]
137    ///     ];
138    ///     let utxos = client.get_asset_utxos(&asset_list, Some(true)).await?;
139    ///     println!("Asset UTXOs: {:?}", utxos);
140    ///     Ok(())
141    /// }
142    /// ```
143    pub async fn get_asset_utxos(
144        &self,
145        asset_list: &[Vec<String>],
146        extended: Option<bool>,
147    ) -> Result<Vec<UtxoInfo>> {
148        let request = AssetListWithExtendedRequest::new(asset_list.to_vec(), extended);
149        self.post("/asset_utxos", &request).await
150    }
151
152    /// Get the mint/burn history of an asset
153    ///
154    /// # Arguments
155    ///
156    /// * `policy_id` - Policy ID to query
157    /// * `asset_name` - Asset name to query
158    ///
159    /// # Examples
160    ///
161    /// ```no_run
162    /// use koios_sdk::Client;
163    /// use koios_sdk::types::{AssetPolicy, AssetName};
164    ///
165    /// #[tokio::main]
166    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
167    ///     let client = Client::new()?;
168    ///     let policy_id = AssetPolicy::new(
169    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
170    ///     );
171    ///     let asset_name = AssetName::new("token1");
172    ///     let history = client.get_asset_history(&policy_id, &asset_name).await?;
173    ///     println!("Asset history: {:?}", history);
174    ///     Ok(())
175    /// }
176    /// ```
177    pub async fn get_asset_history(
178        &self,
179        policy_id: &AssetPolicy,
180        asset_name: &AssetName,
181    ) -> Result<Vec<AssetHistory>> {
182        self.get(&format!(
183            "/asset_history?_asset_policy={}&_asset_name={}",
184            encode(policy_id.value()),
185            encode(asset_name.value())
186        ))
187        .await
188    }
189
190    /// Get the address where specified NFT currently resides
191    ///
192    /// # Arguments
193    ///
194    /// * `policy_id` - NFT policy ID to query
195    /// * `asset_name` - NFT asset name to query
196    ///
197    /// # Examples
198    ///
199    /// ```no_run
200    /// use koios_sdk::Client;
201    /// use koios_sdk::types::{AssetPolicyNft, AssetNameNft};
202    ///
203    /// #[tokio::main]
204    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
205    ///     let client = Client::new()?;
206    ///     let policy_id = AssetPolicyNft::new(
207    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
208    ///     );
209    ///     let asset_name = AssetNameNft::new("nft1");
210    ///     let address = client.get_asset_nft_address(&policy_id, &asset_name).await?;
211    ///     println!("NFT address: {:?}", address);
212    ///     Ok(())
213    /// }
214    /// ```
215    pub async fn get_asset_nft_address(
216        &self,
217        policy_id: &AssetPolicyNft,
218        asset_name: &AssetNameNft,
219    ) -> Result<Vec<AssetNftAddress>> {
220        self.get(&format!(
221            "/asset_nft_address?_asset_policy_nft={}&_asset_name_nft={}",
222            encode(policy_id.value()),
223            encode(asset_name.value())
224        ))
225        .await
226    }
227
228    /// Get the list of addresses with quantity for each asset on the given policy
229    ///
230    /// # Arguments
231    ///
232    /// * `policy_id` - Policy ID to query
233    ///
234    /// # Examples
235    ///
236    /// ```no_run
237    /// use koios_sdk::Client;
238    /// use koios_sdk::types::AssetPolicy;
239    ///
240    /// #[tokio::main]
241    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
242    ///     let client = Client::new()?;
243    ///     let policy_id = AssetPolicy::new(
244    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
245    ///     );
246    ///     let addresses = client.get_policy_asset_addresses(&policy_id).await?;
247    ///     println!("Policy asset addresses: {:?}", addresses);
248    ///     Ok(())
249    /// }
250    /// ```
251    pub async fn get_policy_asset_addresses(
252        &self,
253        policy_id: &AssetPolicy,
254    ) -> Result<Vec<PolicyAssetAddresses>> {
255        self.get(&format!(
256            "/policy_asset_addresses?_asset_policy={}",
257            encode(policy_id.value())
258        ))
259        .await
260    }
261
262    /// Get the information for all assets under the same policy
263    ///
264    /// # Arguments
265    ///
266    /// * `policy_id` - Policy ID to query
267    ///
268    /// # Examples
269    ///
270    /// ```no_run
271    /// use koios_sdk::Client;
272    /// use koios_sdk::types::AssetPolicy;
273    ///
274    /// #[tokio::main]
275    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
276    ///     let client = Client::new()?;
277    ///     let policy_id = AssetPolicy::new(
278    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
279    ///     );
280    ///     let info = client.get_policy_asset_info(&policy_id).await?;
281    ///     println!("Policy asset info: {:?}", info);
282    ///     Ok(())
283    /// }
284    /// ```
285    pub async fn get_policy_asset_info(
286        &self,
287        policy_id: &AssetPolicy,
288    ) -> Result<Vec<PolicyAssetInfo>> {
289        self.get(&format!(
290            "/policy_asset_info?_asset_policy={}",
291            encode(policy_id.value())
292        ))
293        .await
294    }
295
296    /// Get a list of mint or burn count details for all assets minted under a policy
297    ///
298    /// # Arguments
299    ///
300    /// * `policy_id` - Policy ID to query
301    ///
302    /// # Examples
303    ///
304    /// ```no_run
305    /// use koios_sdk::Client;
306    /// use koios_sdk::types::AssetPolicy;
307    ///
308    /// #[tokio::main]
309    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
310    ///     let client = Client::new()?;
311    ///     let policy_id = AssetPolicy::new(
312    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
313    ///     );
314    ///     let mints = client.get_policy_asset_mints(&policy_id).await?;
315    ///     println!("Policy asset mints: {:?}", mints);
316    ///     Ok(())
317    /// }
318    /// ```
319    pub async fn get_policy_asset_mints(
320        &self,
321        policy_id: &AssetPolicy,
322    ) -> Result<Vec<PolicyAssetMint>> {
323        self.get(&format!(
324            "/policy_asset_mints?_asset_policy={}",
325            encode(policy_id.value())
326        ))
327        .await
328    }
329
330    /// Get the summary of an asset
331    ///
332    /// # Arguments
333    ///
334    /// * `policy_id` - Policy ID to query
335    /// * `asset_name` - Asset name to query
336    ///
337    /// # Examples
338    ///
339    /// ```no_run
340    /// use koios_sdk::Client;
341    /// use koios_sdk::types::{AssetPolicy, AssetName};
342    ///
343    /// #[tokio::main]
344    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
345    ///     let client = Client::new()?;
346    ///     let policy_id = AssetPolicy::new(
347    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
348    ///     );
349    ///     let asset_name = AssetName::new("token1");
350    ///     let summary = client.get_asset_summary(&policy_id, &asset_name).await?;
351    ///     println!("Asset summary: {:?}", summary);
352    ///     Ok(())
353    /// }
354    /// ```
355    pub async fn get_asset_summary(
356        &self,
357        policy_id: &AssetPolicy,
358        asset_name: &AssetName,
359    ) -> Result<Vec<AssetSummary>> {
360        self.get(&format!(
361            "/asset_summary?_asset_policy={}&_asset_name={}",
362            encode(policy_id.value()),
363            encode(asset_name.value())
364        ))
365        .await
366    }
367
368    /// Get the list of current or all asset transaction hashes
369    ///
370    /// # Arguments
371    ///
372    /// * `policy_id` - Policy ID to query
373    /// * `asset_name` - Asset name to query
374    /// * `after_block_height` - Optional block height to filter from
375    /// * `history` - Optional flag to include historical transactions
376    ///
377    /// # Examples
378    ///
379    /// ```no_run
380    /// use koios_sdk::Client;
381    /// use koios_sdk::types::{AssetPolicy, AssetName, AfterBlockHeight};
382    ///
383    /// #[tokio::main]
384    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
385    ///     let client = Client::new()?;
386    ///     let policy_id = AssetPolicy::new(
387    ///         "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
388    ///     );
389    ///     let asset_name = AssetName::new("token1");
390    ///     let txs = client.get_asset_transactions(
391    ///         &policy_id,
392    ///         &asset_name,
393    ///         Some(AfterBlockHeight::new(42000000)),
394    ///         Some(true)
395    ///     ).await?;
396    ///     println!("Asset transactions: {:?}", txs);
397    ///     Ok(())
398    /// }
399    /// ```
400    pub async fn get_asset_transactions(
401        &self,
402        policy_id: &AssetPolicy,
403        asset_name: &AssetName,
404        after_block_height: Option<AfterBlockHeight>,
405        history: Option<bool>,
406    ) -> Result<Vec<AddressTransaction>> {
407        let mut endpoint = format!(
408            "/asset_txs?_asset_policy={}&_asset_name={}",
409            encode(policy_id.value()),
410            encode(asset_name.value())
411        );
412
413        if let Some(height) = after_block_height {
414            endpoint.push_str(&format!("&_after_block_height={}", height.value()));
415        }
416
417        if let Some(include_history) = history {
418            endpoint.push_str(&format!("&_history={}", include_history));
419        }
420
421        self.get(&endpoint).await
422    }
423}
424
425#[cfg(test)]
426mod tests {
427    use super::*;
428    use serde_json::json;
429    use wiremock::matchers::{method, path, query_param};
430    use wiremock::{Mock, MockServer, ResponseTemplate};
431
432    #[tokio::test]
433    async fn test_get_asset_list() {
434        let mock_server = MockServer::start().await;
435        let client = Client::builder()
436            .base_url(mock_server.uri())
437            .build()
438            .unwrap();
439
440        let mock_response = json!([{
441            "policy_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209",
442            "asset_name": "token1",
443            "asset_name_ascii": "token1",
444            "fingerprint": "asset1sl88uq7vjx4vf7qq98v5vjml8ufztrs9tq9l4m"
445        }]);
446
447        Mock::given(method("GET"))
448            .and(path("/asset_list"))
449            .respond_with(ResponseTemplate::new(200).set_body_json(&mock_response))
450            .mount(&mock_server)
451            .await;
452
453        let response = client.get_asset_list().await.unwrap();
454        assert_eq!(response.len(), 1);
455        assert_eq!(
456            response[0].policy_id,
457            "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209"
458        );
459    }
460
461    #[tokio::test]
462    async fn test_get_policy_asset_info() {
463        let mock_server = MockServer::start().await;
464        let client = Client::builder()
465            .base_url(mock_server.uri())
466            .build()
467            .unwrap();
468
469        let policy_id = "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209";
470        let mock_response = json!([{
471            "asset_name": "token1",
472            "asset_name_ascii": "token1",
473            "fingerprint": "asset1sl88uq7vjx4vf7qq98v5vjml8ufztrs9tq9l4m",
474            "minting_tx_hash": "6ed09ba58a56c6e946668038ba4d3cef8eb97a20cbf76c5970e1402e8a8d6541",
475            "total_supply": "1000",
476            "mint_cnt": 1,
477            "burn_cnt": 0,
478            "creation_time": 1628222400,
479            "minting_tx_metadata": null,
480            "token_registry_metadata": null
481        }]);
482
483        Mock::given(method("GET"))
484            .and(path("/policy_asset_info"))
485            .and(query_param("_asset_policy", policy_id))
486            .respond_with(ResponseTemplate::new(200).set_body_json(&mock_response))
487            .mount(&mock_server)
488            .await;
489
490        let response = client
491            .get_policy_asset_info(&AssetPolicy::new(policy_id))
492            .await
493            .unwrap();
494        assert_eq!(response.len(), 1);
495        assert_eq!(response[0].asset_name, "token1");
496    }
497
498    // Add more tests for other endpoints...
499}