eth_icons/modules/
blockscout.rs1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{Error, IconFetcher, IconQuery, IconResult, IconSource};
6
7#[derive(Clone)]
8pub struct Blockscout;
9
10#[async_trait::async_trait]
11impl IconSource for Blockscout {
12 fn name(&self) -> &'static str {
13 "blockscout"
14 }
15
16 fn url(&self, query: &IconQuery) -> Option<String> {
17 match query {
18 IconQuery::ERC20(network_id, address) => {
19 if *network_id != 1 {
20 return None;
21 }
22 Some(format!(
23 "https://eth.blockscout.com/api/v2/tokens/{}",
24 address.to_lowercase()
25 ))
26 }
27 _ => None,
28 }
29 }
30
31 async fn fetch(&self, fetcher: &IconFetcher, query: &IconQuery) -> Result<IconResult, Error> {
32 let Some(url) = self.url(query) else {
33 return Ok(IconResult::Unsupported);
34 };
35
36 let Some(metadata) = fetcher.fetch_json::<BlockscoutAssetMetadata>(&url).await? else {
37 return Ok(IconResult::NotFound);
38 };
39
40 let Some(icon_url) = metadata.icon_url else {
41 return Ok(IconResult::NotFound);
42 };
43
44 fetcher.fetch_image_url(&icon_url).await
45 }
46}
47
48#[derive(Debug, Serialize, Deserialize)]
49pub struct BlockscoutAssetMetadata {
50 pub icon_url: Option<String>,
51 #[serde(flatten)]
52 pub other: HashMap<String, serde_json::Value>,
53}