Skip to main content

eth_icons/modules/
blockscout.rs

1use 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}