From 1625a2c677b87c3d7ea5503dc40bf01cb63c5ba7 Mon Sep 17 00:00:00 2001 From: Leonid Tyurin Date: Thu, 3 Oct 2024 14:43:16 +0700 Subject: [PATCH] feat: add blockscout-chains crate --- libs/Cargo.toml | 1 + libs/blockscout-chains/Cargo.toml | 17 +++++++++ libs/blockscout-chains/src/lib.rs | 58 +++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 libs/blockscout-chains/Cargo.toml create mode 100644 libs/blockscout-chains/src/lib.rs diff --git a/libs/Cargo.toml b/libs/Cargo.toml index 5bc341951..3c6c0ef53 100644 --- a/libs/Cargo.toml +++ b/libs/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "blockscout-auth", + "blockscout-chains", "blockscout-client/crate", "blockscout-db", "endpoints/swagger", diff --git a/libs/blockscout-chains/Cargo.toml b/libs/blockscout-chains/Cargo.toml new file mode 100644 index 000000000..63165226f --- /dev/null +++ b/libs/blockscout-chains/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "blockscout-chains" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1" +reqwest = { version = "0.12", features = ["json"] } +reqwest-middleware = "0.3" +reqwest-retry = "0.6" + +[dev-dependencies] +tokio = { version = "1.0", features = ["macros"] } diff --git a/libs/blockscout-chains/src/lib.rs b/libs/blockscout-chains/src/lib.rs new file mode 100644 index 000000000..782d23ddc --- /dev/null +++ b/libs/blockscout-chains/src/lib.rs @@ -0,0 +1,58 @@ +use reqwest_middleware::ClientBuilder; +use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; +use serde::Deserialize; +use std::collections::HashMap; + +const CHAINS_URL: &str = "https://chains.blockscout.com/api/chains"; + +pub async fn get_blockscout_chains() -> anyhow::Result { + let max_retries = 3; + let retry_policy = ExponentialBackoff::builder().build_with_max_retries(max_retries); + let client = ClientBuilder::new(reqwest::Client::new()) + .with(RetryTransientMiddleware::new_with_policy(retry_policy)) + .build(); + let res = client.get(CHAINS_URL).send().await?; + let chains: BlockscoutChains = res.json().await?; + Ok(chains) +} + +pub type BlockscoutChains = HashMap; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct BlockscoutChainData { + pub name: String, + pub description: String, + pub ecosystem: Ecosystem, + pub is_testnet: Option, + pub layer: Option, + pub rollup_type: Option, + pub website: String, + pub explorers: Vec, + pub logo: String, +} + +#[derive(Deserialize, Debug)] +#[serde(untagged)] +pub enum Ecosystem { + Single(String), + Multiple(Vec), +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ExplorerConfig { + pub url: String, + pub hosted_by: String, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_get_blockscout_chains() { + let chains = get_blockscout_chains().await.unwrap(); + assert!(!chains.is_empty()); + } +}