ethers_abirpc/
providers.rs1use {
2 crate::{
3 chain::{Chain, RetryClientConfig},
4 error::Error,
5 },
6 async_trait::async_trait,
7 ethers::{
8 providers::{
9 Http, HttpRateLimitRetryPolicy, Ipc, Middleware, Provider, RetryClient,
10 RetryClientBuilder, Ws,
11 },
12 types::U256,
13 },
14 std::{path::Path, time::Duration},
15 url::Url,
16};
17
18pub type HttpTransport = Http;
19
20pub type HttpProvider = Provider<HttpTransport>;
21
22pub type WsTransport = Ws;
23
24pub type WsProvider = Provider<WsTransport>;
25
26pub type IpcTransport = Ipc;
27
28pub type IpcProvider = Provider<IpcTransport>;
29
30pub type RetryTransport = RetryClient<Http>;
31
32pub type RetryProvider = Provider<RetryTransport>;
33
34pub type MockProvider = Provider<ethers::providers::MockProvider>;
35
36#[async_trait]
37pub trait AbiProviderTrait<M>
38where
39 M: Middleware,
40{
41 async fn provider(&self) -> Result<M, Error>;
42}
43
44pub struct AbiProvider {
45 pub url: Option<String>,
46 pub chain: Option<Chain>,
47}
48
49impl AbiProvider {
50 pub fn _new(url: Option<String>, chain: Option<Chain>) -> Self {
51 Self { url, chain }
52 }
53
54 pub fn new(url: String, chain: Chain) -> Self {
55 Self {
56 url: Some(url),
57 chain: Some(chain),
58 }
59 }
60
61 pub fn mock() -> Self {
62 Self {
63 url: None,
64 chain: None,
65 }
66 }
67}
68
69macro_rules! assert_chain_id {
70 ($chain: expr, $provider: expr) => {
71 if let Some(chain) = $chain {
72 if chain.assert_chain_id() {
73 let provider_chain_id = $provider.get_chainid().await?;
74 if U256::from(chain.id()) != provider_chain_id {
75 let e = format!(
76 "Configured chain_id ({}) does not match chain ({})",
77 U256::from(chain.id()),
78 provider_chain_id
79 );
80 return Err(Error::ChainIdError(e));
81 }
82 }
83 }
84 };
85}
86
87#[async_trait]
88impl AbiProviderTrait<WsProvider> for AbiProvider {
89 async fn provider(&self) -> Result<WsProvider, Error> {
90 match &self.url {
91 Some(url) => {
92 let url = Url::parse(url)?;
93 let provider = Provider::<WsTransport>::connect(url).await?;
94 assert_chain_id!(self.chain, provider);
95 Ok(provider)
96 }
97 None => Err(Error::Error(String::from("Provider url is None"))),
98 }
99 }
100}
101
102#[async_trait]
103impl AbiProviderTrait<IpcProvider> for AbiProvider {
104 async fn provider(&self) -> Result<IpcProvider, Error> {
105 match &self.url {
106 Some(url) => {
107 let provider = Provider::<IpcTransport>::connect_ipc(Path::new(&url)).await?;
108 assert_chain_id!(self.chain, provider);
109 Ok(provider)
110 }
111 None => Err(Error::Error(String::from("Provider url is None"))),
112 }
113 }
114}
115
116#[async_trait]
117impl AbiProviderTrait<HttpProvider> for AbiProvider {
118 async fn provider(&self) -> Result<HttpProvider, Error> {
119 match &self.url {
120 Some(url) => {
121 let url = Url::parse(url)?;
122 let provider = Provider::<HttpTransport>::new(Http::new(url));
123 assert_chain_id!(self.chain, provider);
124 Ok(provider)
125 }
126 None => Err(Error::Error(String::from("Provider url is None"))),
127 }
128 }
129}
130
131#[async_trait]
132impl AbiProviderTrait<RetryProvider> for AbiProvider {
133 async fn provider(&self) -> Result<RetryProvider, Error> {
134 match &self.url {
135 Some(url) => {
136 let url = Url::parse(url)?;
137 let retry_config = match self.chain {
138 Some(chain) => chain.retry_client_config(),
139 None => RetryClientConfig::default(),
140 };
141
142 let provider = Provider::new(
143 RetryClientBuilder::default()
144 .rate_limit_retries(retry_config.rate_limit_retries)
145 .timeout_retries(retry_config.timeout_retries)
146 .initial_backoff(Duration::from_millis(retry_config.initial_backoff_ms))
147 .build(Http::new(url), Box::new(HttpRateLimitRetryPolicy)),
148 );
149 assert_chain_id!(self.chain, provider);
150 Ok(provider)
151 }
152 None => Err(Error::Error(String::from("Provider url is None"))),
153 }
154 }
155}
156
157#[async_trait]
158impl AbiProviderTrait<MockProvider> for AbiProvider {
159 async fn provider(&self) -> Result<MockProvider, Error> {
160 match &self.url {
161 Some(_) => Err(Error::Error(String::from("MockProvider url is not None"))),
162 None => {
163 let (provider, _mock) = Provider::mocked();
164 Ok(provider)
165 }
166 }
167 }
168}