1use alloy_eips::BlockId;
2use alloy_json_rpc::{RpcRecv, RpcSend};
3use alloy_primitives::B256;
4use alloy_rpc_client::RpcCall;
5use alloy_transport::TransportResult;
6use std::future::IntoFuture;
7
8use crate::ProviderCall;
9
10#[derive(Debug, Clone)]
12pub struct ParamsWithBlock<Params: RpcSend> {
13 pub params: Params,
15 pub block_id: BlockId,
17}
18
19impl<Params: RpcSend> ParamsWithBlock<Params> {
20 pub fn new(params: Params, block_id: BlockId) -> Self {
22 Self { params, block_id }
23 }
24}
25
26impl<Params: RpcSend> serde::Serialize for ParamsWithBlock<Params> {
27 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28 where
29 S: serde::Serializer,
30 {
31 let mut ser = serde_json::to_value(&self.params).map_err(serde::ser::Error::custom)?;
33
34 let block_id = serde_json::to_value(self.block_id).map_err(serde::ser::Error::custom)?;
36
37 if let serde_json::Value::Array(ref mut arr) = ser {
38 arr.push(block_id);
39 } else if ser.is_null() {
40 ser = serde_json::Value::Array(vec![block_id]);
41 } else {
42 ser = serde_json::Value::Array(vec![ser, block_id]);
43 }
44
45 ser.serialize(serializer)
46 }
47}
48
49type ProviderCallProducer<Params, Resp, Output, Map> =
50 Box<dyn Fn(BlockId) -> ProviderCall<ParamsWithBlock<Params>, Resp, Output, Map> + Send>;
51
52enum WithBlockInner<Params, Resp, Output = Resp, Map = fn(Resp) -> Output>
54where
55 Params: RpcSend,
56 Resp: RpcRecv,
57 Map: Fn(Resp) -> Output,
58{
59 RpcCall(RpcCall<Params, Resp, Output, Map>),
61 ProviderCall(ProviderCallProducer<Params, Resp, Output, Map>),
63}
64
65impl<Params, Resp, Output, Map> core::fmt::Debug for WithBlockInner<Params, Resp, Output, Map>
66where
67 Params: RpcSend,
68 Resp: RpcRecv,
69 Map: Fn(Resp) -> Output,
70{
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 match self {
73 Self::RpcCall(call) => f.debug_tuple("RpcCall").field(call).finish(),
74 Self::ProviderCall(_) => f.debug_struct("ProviderCall").finish(),
75 }
76 }
77}
78
79#[pin_project::pin_project]
85#[derive(Debug)]
86pub struct RpcWithBlock<Params, Resp, Output = Resp, Map = fn(Resp) -> Output>
87where
88 Params: RpcSend,
89 Resp: RpcRecv,
90 Map: Fn(Resp) -> Output + Clone,
91{
92 inner: WithBlockInner<Params, Resp, Output, Map>,
93 block_id: BlockId,
94}
95
96impl<Params, Resp, Output, Map> RpcWithBlock<Params, Resp, Output, Map>
97where
98 Params: RpcSend,
99 Resp: RpcRecv,
100 Map: Fn(Resp) -> Output + Clone,
101{
102 pub fn new_rpc(inner: RpcCall<Params, Resp, Output, Map>) -> Self {
104 Self { inner: WithBlockInner::RpcCall(inner), block_id: Default::default() }
105 }
106
107 pub fn new_provider<F>(get_call: F) -> Self
109 where
110 F: Fn(BlockId) -> ProviderCall<ParamsWithBlock<Params>, Resp, Output, Map> + Send + 'static,
111 {
112 let get_call = Box::new(get_call);
113 Self { inner: WithBlockInner::ProviderCall(get_call), block_id: Default::default() }
114 }
115}
116
117impl<Params, Resp, Output, Map> From<RpcCall<Params, Resp, Output, Map>>
118 for RpcWithBlock<Params, Resp, Output, Map>
119where
120 Params: RpcSend,
121 Resp: RpcRecv,
122 Map: Fn(Resp) -> Output + Clone,
123{
124 fn from(inner: RpcCall<Params, Resp, Output, Map>) -> Self {
125 Self::new_rpc(inner)
126 }
127}
128
129impl<F, Params, Resp, Output, Map> From<F> for RpcWithBlock<Params, Resp, Output, Map>
130where
131 Params: RpcSend,
132 Resp: RpcRecv,
133 Map: Fn(Resp) -> Output + Clone,
134 F: Fn(BlockId) -> ProviderCall<ParamsWithBlock<Params>, Resp, Output, Map> + Send + 'static,
135{
136 fn from(inner: F) -> Self {
137 Self::new_provider(inner)
138 }
139}
140
141impl<Params, Resp, Output, Map> RpcWithBlock<Params, Resp, Output, Map>
142where
143 Params: RpcSend,
144 Resp: RpcRecv,
145 Map: Fn(Resp) -> Output + Clone,
146{
147 pub const fn block_id(mut self, block_id: BlockId) -> Self {
149 self.block_id = block_id;
150 self
151 }
152
153 pub const fn pending(self) -> Self {
155 self.block_id(BlockId::pending())
156 }
157
158 pub const fn latest(self) -> Self {
160 self.block_id(BlockId::latest())
161 }
162
163 pub const fn earliest(self) -> Self {
165 self.block_id(BlockId::earliest())
166 }
167
168 pub const fn finalized(self) -> Self {
170 self.block_id(BlockId::finalized())
171 }
172
173 pub const fn safe(self) -> Self {
175 self.block_id(BlockId::safe())
176 }
177
178 pub const fn number(self, number: u64) -> Self {
180 self.block_id(BlockId::number(number))
181 }
182
183 pub const fn hash(self, hash: B256) -> Self {
186 self.block_id(BlockId::hash(hash))
187 }
188
189 pub const fn hash_canonical(self, hash: B256) -> Self {
192 self.block_id(BlockId::hash_canonical(hash))
193 }
194}
195
196impl<Params, Resp, Output, Map> IntoFuture for RpcWithBlock<Params, Resp, Output, Map>
197where
198 Params: RpcSend,
199 Resp: RpcRecv,
200 Output: 'static,
201 Map: Fn(Resp) -> Output + Clone,
202{
203 type Output = TransportResult<Output>;
204
205 type IntoFuture = ProviderCall<ParamsWithBlock<Params>, Resp, Output, Map>;
206
207 fn into_future(self) -> Self::IntoFuture {
208 match self.inner {
209 WithBlockInner::RpcCall(rpc_call) => {
210 let block_id = self.block_id;
211 let rpc_call = rpc_call.map_params(|params| ParamsWithBlock::new(params, block_id));
212 ProviderCall::RpcCall(rpc_call)
213 }
214 WithBlockInner::ProviderCall(get_call) => get_call(self.block_id),
215 }
216 }
217}