1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#![doc = include_str!("../README.md")]
#![allow(clippy::type_complexity)]
#![warn(missing_docs)]
#![deny(unsafe_code, rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

mod ext;
pub use ext::*;

mod rpc;
pub use rpc::*;

mod toolbox;
pub use toolbox::*;

/// Crate utilities and type aliases
mod utils;
pub use utils::{interval, maybe, EscalationPolicy};

/// Errors
mod errors;
pub use errors::{MiddlewareError, ProviderError, RpcError};

mod stream;
pub use futures_util::StreamExt;
pub use stream::{
    tx_stream::TransactionStream, FilterWatcher, DEFAULT_LOCAL_POLL_INTERVAL, DEFAULT_POLL_INTERVAL,
};

mod middleware;
#[cfg(feature = "celo")]
pub use middleware::CeloMiddleware;
pub use middleware::Middleware;

#[allow(deprecated)]
pub use test_provider::{GOERLI, MAINNET, ROPSTEN, SEPOLIA};

/// Pre-instantiated Infura HTTP clients which rotate through multiple API keys
/// to prevent rate limits
#[allow(missing_docs)]
pub mod test_provider {
    use super::*;
    use once_cell::sync::Lazy;
    use std::{iter::Cycle, slice::Iter, sync::Mutex};

    // List of infura keys to rotate through so we don't get rate limited
    const INFURA_KEYS: &[&str] = &["15e8aaed6f894d63a0f6a0206c006cdd"];

    pub static MAINNET: Lazy<TestProvider> =
        Lazy::new(|| TestProvider::new(INFURA_KEYS, "mainnet"));
    pub static GOERLI: Lazy<TestProvider> = Lazy::new(|| TestProvider::new(INFURA_KEYS, "goerli"));
    pub static SEPOLIA: Lazy<TestProvider> =
        Lazy::new(|| TestProvider::new(INFURA_KEYS, "sepolia"));

    #[deprecated = "Ropsten testnet has been deprecated in favor of Goerli or Sepolia."]
    pub static ROPSTEN: Lazy<TestProvider> =
        Lazy::new(|| TestProvider::new(INFURA_KEYS, "ropsten"));

    #[derive(Debug)]
    pub struct TestProvider {
        network: String,
        keys: Mutex<Cycle<Iter<'static, &'static str>>>,
    }

    impl TestProvider {
        pub fn new(keys: &'static [&'static str], network: impl Into<String>) -> Self {
            Self { keys: keys.iter().cycle().into(), network: network.into() }
        }

        pub fn url(&self) -> String {
            let Self { network, keys } = self;
            let key = keys.lock().unwrap().next().unwrap();
            format!("https://{network}.infura.io/v3/{key}")
        }

        pub fn provider(&self) -> Provider<Http> {
            Provider::try_from(self.url().as_str()).unwrap()
        }

        #[cfg(feature = "ws")]
        pub async fn ws(&self) -> Provider<crate::Ws> {
            let url = format!(
                "wss://{}.infura.io/ws/v3/{}",
                self.network,
                self.keys.lock().unwrap().next().unwrap()
            );
            Provider::connect(url.as_str()).await.unwrap()
        }
    }
}