starkli 0.1.3

Starkli (/ˈstɑːrklaɪ/), a blazing fast CLI tool for Starknet powered by starknet-rs
use std::{fmt::Display, str::FromStr};

use anyhow::Result;
use async_trait::async_trait;
use auto_impl::auto_impl;
use clap::{builder::PossibleValue, ValueEnum};
use starknet::providers::Provider;

use crate::provider::ExtendedProvider;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Network {
    Mainnet,
    Goerli1,
    Goerli2,
    Integration,
}

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[auto_impl(&, Box, Arc)]
pub trait NetworkSource {
    async fn get_network(&self) -> Result<Option<Network>>;
}

impl ValueEnum for Network {
    fn value_variants<'a>() -> &'a [Self] {
        &[
            Self::Mainnet,
            Self::Goerli1,
            Self::Goerli2,
            Self::Integration,
        ]
    }

    fn to_possible_value(&self) -> Option<PossibleValue> {
        match self {
            Network::Mainnet => Some(PossibleValue::new("mainnet").aliases(["alpha-mainnet"])),
            Network::Goerli1 => Some(PossibleValue::new("goerli-1").aliases([
                "goerli",
                "goerli1",
                "alpha-goerli",
                "alpha-goerli1",
                "alpha-goerli-1",
            ])),
            Network::Goerli2 => Some(PossibleValue::new("goerli-2").aliases([
                "goerli2",
                "alpha-goerli2",
                "alpha-goerli-2",
            ])),
            Network::Integration => Some(PossibleValue::new("integration")),
        }
    }
}

impl FromStr for Network {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self> {
        match s {
            "mainnet" | "alpha-mainnet" => Ok(Self::Mainnet),
            "goerli" | "goerli1" | "goerli-1" | "alpha-goerli" | "alpha-goerli1"
            | "alpha-goerli-1" => Ok(Self::Goerli1),
            "goerli2" | "goerli-2" | "alpha-goerli2" | "alpha-goerli-2" => Ok(Self::Goerli2),
            "integration" => Ok(Self::Integration),
            _ => Err(anyhow::anyhow!("unknown network: {}", s)),
        }
    }
}

impl Display for Network {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Mainnet => write!(f, "mainnet"),
            Self::Goerli1 => write!(f, "goerli-1"),
            Self::Goerli2 => write!(f, "goerli-2"),
            Self::Integration => write!(f, "integration"),
        }
    }
}

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl NetworkSource for ExtendedProvider {
    async fn get_network(&self) -> Result<Option<Network>> {
        let chain_id = self.chain_id().await?;
        let is_integration = self.is_integration();

        Ok(if is_integration {
            if chain_id == starknet::core::chain_id::TESTNET {
                Some(Network::Integration)
            } else {
                None
            }
        } else if chain_id == starknet::core::chain_id::MAINNET {
            Some(Network::Mainnet)
        } else if chain_id == starknet::core::chain_id::TESTNET {
            Some(Network::Goerli1)
        } else if chain_id == starknet::core::chain_id::TESTNET2 {
            Some(Network::Goerli2)
        } else {
            None
        })
    }
}