mwc_web3/
lib.rs

1//! Ethereum JSON-RPC client (Web3).
2
3#![allow(
4    clippy::type_complexity,
5    clippy::wrong_self_convention,
6    clippy::single_match,
7    clippy::let_unit_value,
8    clippy::match_wild_err_arm
9)]
10#![warn(missing_docs)]
11// select! in WS transport
12#![recursion_limit = "256"]
13
14use jsonrpc_core as rpc;
15
16/// Re-export of the `futures` crate.
17#[macro_use]
18pub extern crate futures;
19pub use futures::executor::{block_on, block_on_stream};
20
21pub use ethabi;
22
23// it needs to be before other modules
24// otherwise the macro for tests is not available.
25#[macro_use]
26pub mod helpers;
27
28pub mod api;
29pub mod confirm;
30pub mod contract;
31pub mod error;
32pub mod signing;
33pub mod transports;
34pub mod types;
35
36pub use crate::{
37    api::Web3,
38    error::{Error, Result},
39};
40
41/// Assigned RequestId
42pub type RequestId = usize;
43
44// TODO [ToDr] The transport most likely don't need to be thread-safe.
45// (though it has to be Send)
46/// Transport implementation
47pub trait Transport: std::fmt::Debug + Clone {
48    /// The type of future this transport returns when a call is made.
49    type Out: futures::Future<Output = error::Result<rpc::Value>>;
50
51    /// Prepare serializable RPC call for given method with parameters.
52    fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call);
53
54    /// Execute prepared RPC call.
55    fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out;
56
57    /// Execute remote method with given parameters.
58    fn execute(&self, method: &str, params: Vec<rpc::Value>) -> Self::Out {
59        let (id, request) = self.prepare(method, params);
60        self.send(id, request)
61    }
62}
63
64/// A transport implementation supporting batch requests.
65pub trait BatchTransport: Transport {
66    /// The type of future this transport returns when a call is made.
67    type Batch: futures::Future<Output = error::Result<Vec<error::Result<rpc::Value>>>>;
68
69    /// Sends a batch of prepared RPC calls.
70    fn send_batch<T>(&self, requests: T) -> Self::Batch
71    where
72        T: IntoIterator<Item = (RequestId, rpc::Call)>;
73}
74
75/// A transport implementation supporting pub sub subscriptions.
76pub trait DuplexTransport: Transport {
77    /// The type of stream this transport returns
78    type NotificationStream: futures::Stream<Item = rpc::Value>;
79
80    /// Add a subscription to this transport
81    fn subscribe(&self, id: api::SubscriptionId) -> error::Result<Self::NotificationStream>;
82
83    /// Remove a subscription from this transport
84    fn unsubscribe(&self, id: api::SubscriptionId) -> error::Result<()>;
85}
86
87impl<X, T> Transport for X
88where
89    T: Transport + ?Sized,
90    X: std::ops::Deref<Target = T>,
91    X: std::fmt::Debug,
92    X: Clone,
93{
94    type Out = T::Out;
95
96    fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
97        (**self).prepare(method, params)
98    }
99
100    fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
101        (**self).send(id, request)
102    }
103}
104
105impl<X, T> BatchTransport for X
106where
107    T: BatchTransport + ?Sized,
108    X: std::ops::Deref<Target = T>,
109    X: std::fmt::Debug,
110    X: Clone,
111{
112    type Batch = T::Batch;
113
114    fn send_batch<I>(&self, requests: I) -> Self::Batch
115    where
116        I: IntoIterator<Item = (RequestId, rpc::Call)>,
117    {
118        (**self).send_batch(requests)
119    }
120}
121
122impl<X, T> DuplexTransport for X
123where
124    T: DuplexTransport + ?Sized,
125    X: std::ops::Deref<Target = T>,
126    X: std::fmt::Debug,
127    X: Clone,
128{
129    type NotificationStream = T::NotificationStream;
130
131    fn subscribe(&self, id: api::SubscriptionId) -> error::Result<Self::NotificationStream> {
132        (**self).subscribe(id)
133    }
134
135    fn unsubscribe(&self, id: api::SubscriptionId) -> error::Result<()> {
136        (**self).unsubscribe(id)
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::{error, rpc, RequestId, Transport};
143
144    use crate::api::Web3;
145    use futures::future::BoxFuture;
146    use std::sync::Arc;
147
148    #[derive(Debug, Clone)]
149    struct FakeTransport;
150
151    impl Transport for FakeTransport {
152        type Out = BoxFuture<'static, error::Result<rpc::Value>>;
153
154        fn prepare(&self, _method: &str, _params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
155            unimplemented!()
156        }
157
158        fn send(&self, _id: RequestId, _request: rpc::Call) -> Self::Out {
159            unimplemented!()
160        }
161    }
162
163    #[test]
164    fn should_allow_to_use_arc_as_transport() {
165        let transport = Arc::new(FakeTransport);
166        let transport2 = transport.clone();
167
168        let _web3_1 = Web3::new(transport);
169        let _web3_2 = Web3::new(transport2);
170    }
171}