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}