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