ethers-abirpc 0.3.0

ethers-rs provider encapsulation for ethereum smart contrcats
Documentation
use {
    crate::chain::Chain,
    ethers::types::Address,
    std::{
        clone::Clone,
        collections::HashMap,
        sync::{Arc, RwLock},
    },
};

#[derive(Debug)]
pub struct AbiRegistry<C> {
    pub url: Option<String>,
    pub chain: Option<Chain>,
    pub registry: Arc<RwLock<HashMap<Address, C>>>,
}

impl<C> AbiRegistry<C> {
    pub fn new(url: String, chain: Chain) -> Self {
        Self {
            url: Some(url),
            chain: Some(chain),
            registry: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub fn mock() -> Self {
        Self {
            url: None,
            chain: None,
            registry: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub fn entry_exists(&self, address: Address) -> bool {
        let arc_clone = Arc::clone(&self.registry);
        let registry = arc_clone.read().expect("Registry RwLock poisoned!");
        let entry_exists = registry.contains_key(&address);
        drop(registry);

        entry_exists
    }

    pub fn add_entry(&self, address: Address, contract: C) {
        let arc_clone = Arc::clone(&self.registry);
        let mut registry = arc_clone.write().expect("Registry RwLock poisoned!");
        registry.insert(address, contract);
        drop(registry);
    }
}

#[macro_export]
macro_rules! abirpc {
    ($abi:ident) => {
        paste::paste! {

            #[derive(Debug)]
            pub struct [<$abi Registry>]<M>($crate::registry::AbiRegistry<$abi<M>>)
            where
                M: ::ethers::prelude::Middleware;

            #[async_trait::async_trait]
            impl $crate::providers::AbiProviderTrait<$crate::providers::WsProvider>
                for [<$abi Registry>]<$crate::providers::WsProvider>
            {
                async fn provider(
                    &self,
                ) -> Result<$crate::providers::WsProvider, $crate::error::Error> {
                    let provider: $crate::providers::WsProvider =
                        $crate::providers::AbiProvider::_new(self.0.url.clone(), self.0.chain)
                            .provider()
                            .await?;

                    Ok(provider)
                }
            }

            #[async_trait::async_trait]
            impl $crate::providers::AbiProviderTrait<$crate::providers::IpcProvider>
                for [<$abi Registry>]<$crate::providers::IpcProvider>
            {
                async fn provider(
                    &self,
                ) -> Result<$crate::providers::IpcProvider, $crate::error::Error> {
                    let provider: $crate::providers::IpcProvider =
                        $crate::providers::AbiProvider::_new(self.0.url.clone(), self.0.chain)
                            .provider()
                            .await?;

                    Ok(provider)
                }
            }

            #[async_trait::async_trait]
            impl $crate::providers::AbiProviderTrait<$crate::providers::HttpProvider>
                for [<$abi Registry>]<$crate::providers::HttpProvider>
            {
                async fn provider(
                    &self,
                ) -> Result<$crate::providers::HttpProvider, $crate::error::Error> {
                    let provider: $crate::providers::HttpProvider =
                        $crate::providers::AbiProvider::_new(self.0.url.clone(), self.0.chain)
                            .provider()
                            .await?;

                    Ok(provider)
                }
            }

            #[async_trait::async_trait]
            impl $crate::providers::AbiProviderTrait<$crate::providers::RetryProvider>
                for [<$abi Registry>]<$crate::providers::RetryProvider>
            {
                async fn provider(
                    &self,
                ) -> Result<$crate::providers::RetryProvider, $crate::error::Error> {
                    let provider: $crate::providers::RetryProvider =
                        $crate::providers::AbiProvider::_new(self.0.url.clone(), self.0.chain)
                            .provider()
                            .await?;

                    Ok(provider)
                }
            }

            #[async_trait::async_trait]
            impl $crate::providers::AbiProviderTrait<$crate::providers::MockProvider>
                for [<$abi Registry>]<$crate::providers::MockProvider>
            {
                async fn provider(
                    &self,
                ) -> Result<$crate::providers::MockProvider, $crate::error::Error> {
                    let provider: $crate::providers::MockProvider =
                        $crate::providers::AbiProvider::mock().provider().await?;

                    Ok(provider)
                }
            }

            impl<M> [<$abi Registry>]<M>
            where
                M: ::ethers::prelude::Middleware,
            {
                pub fn new(url: String, chain: $crate::chain::Chain) -> Self {
                    let registry = $crate::registry::AbiRegistry::<$abi<M>>::new(url, chain);
                    Self(registry)
                }

                pub fn mock() -> Self {
                    let registry = $crate::registry::AbiRegistry::<$abi<M>>::mock();
                    Self(registry)
                }

                pub fn register(&self, provider: M, address: ::ethers::prelude::Address) -> $abi<M> {
                    if !self.0.entry_exists(address) {
                        let instance = $abi::new(address, provider.into());
                        self.0.add_entry(address, instance)
                    }

                    let clone_lock = std::sync::Arc::clone(&self.0.registry);
                    let registry = clone_lock.read().expect("Registry RwLock poisoned!");
                    let instance = registry.get(&address).unwrap().clone();
                    drop(registry);

                    instance
                }

                pub fn chain(&self) -> Option<$crate::chain::Chain> {
                    self.0.chain
                }
            }

            impl<M> $abi<M>
            where
                M: ::ethers::prelude::Middleware,
            {
                pub async fn get_logs<E>(
                    &self,
                    from_block: ::ethers::prelude::BlockNumber,
                    to_block: ::ethers::prelude::BlockNumber,
                ) -> Result<Vec<E>, $crate::error::Error>
                where
                    E: ethers::prelude::EthEvent + std::fmt::Debug,
                {
                    let res = self
                        .event::<E>()
                        .address(ethers::prelude::ValueOrArray::Value(self.address()))
                        .from_block(from_block)
                        .to_block(to_block)
                        .query()
                        .await?;

                    Ok(res)
                }
            }
        }
    };
}

#[macro_export]
macro_rules! address_from {
    ($address: expr) => {
        $address.parse::<ethers::prelude::Address>()
    };
}