1#[cfg(feature = "pyo3")]
4use anyhow::Context;
5use serde::{Deserialize, Serialize};
6
7#[derive(Default, Debug, Clone)]
9#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
10pub struct Query {
11 pub from_block: u64,
12 pub to_block: Option<u64>,
13 pub include_all_blocks: bool,
14 pub transactions: Vec<TransactionRequest>,
15 pub logs: Vec<LogRequest>,
16 pub traces: Vec<TraceRequest>,
17 pub fields: Fields,
18}
19
20#[derive(Debug, Clone, Copy)]
22pub struct Hash(pub [u8; 32]);
23
24#[derive(Debug, Clone, Copy)]
26pub struct Address(pub [u8; 20]);
27
28#[derive(Debug, Clone, Copy)]
30pub struct Sighash(pub [u8; 4]);
31
32#[derive(Debug, Clone, Copy)]
34pub struct Topic(pub [u8; 32]);
35
36#[cfg(feature = "pyo3")]
37fn extract_hex<const N: usize>(ob: &pyo3::Bound<'_, pyo3::PyAny>) -> pyo3::PyResult<[u8; N]> {
38 use pyo3::types::PyAnyMethods;
39
40 let s: &str = ob.extract()?;
41 let s = s.strip_prefix("0x").context("strip 0x prefix")?;
42 let mut out = [0; N];
43 faster_hex::hex_decode(s.as_bytes(), &mut out).context("decode hex")?;
44
45 Ok(out)
46}
47
48#[cfg(feature = "pyo3")]
49impl<'py> pyo3::FromPyObject<'py> for Hash {
50 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
51 let out = extract_hex(ob)?;
52 Ok(Self(out))
53 }
54}
55
56#[cfg(feature = "pyo3")]
57impl<'py> pyo3::FromPyObject<'py> for Address {
58 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
59 let out = extract_hex(ob)?;
60 Ok(Self(out))
61 }
62}
63
64#[cfg(feature = "pyo3")]
65impl<'py> pyo3::FromPyObject<'py> for Sighash {
66 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
67 let out = extract_hex(ob)?;
68 Ok(Self(out))
69 }
70}
71
72#[cfg(feature = "pyo3")]
73impl<'py> pyo3::FromPyObject<'py> for Topic {
74 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
75 let out = extract_hex(ob)?;
76 Ok(Self(out))
77 }
78}
79
80#[derive(Default, Debug, Clone)]
82#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
83pub struct TransactionRequest {
84 pub from_: Vec<Address>,
85 pub to: Vec<Address>,
86 pub sighash: Vec<Sighash>,
87 pub status: Vec<u8>,
88 pub type_: Vec<u8>,
89 pub contract_deployment_address: Vec<Address>,
90 pub hash: Vec<Hash>,
91 pub include_logs: bool,
92 pub include_traces: bool,
93 pub include_blocks: bool,
94}
95
96#[derive(Default, Debug, Clone)]
98#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
99#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
100pub struct LogRequest {
101 pub address: Vec<Address>,
102 pub topic0: Vec<Topic>,
103 pub topic1: Vec<Topic>,
104 pub topic2: Vec<Topic>,
105 pub topic3: Vec<Topic>,
106 pub include_transactions: bool,
107 pub include_transaction_logs: bool,
108 pub include_transaction_traces: bool,
109 pub include_blocks: bool,
110}
111
112#[derive(Default, Debug, Clone)]
114#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
115#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
116pub struct TraceRequest {
117 pub from_: Vec<Address>,
118 pub to: Vec<Address>,
119 pub address: Vec<Address>,
120 pub call_type: Vec<String>,
121 pub reward_type: Vec<String>,
122 pub type_: Vec<String>,
123 pub sighash: Vec<Sighash>,
124 pub author: Vec<Address>,
125 pub include_transactions: bool,
126 pub include_transaction_logs: bool,
127 pub include_transaction_traces: bool,
128 pub include_blocks: bool,
129}
130
131#[derive(Deserialize, Serialize, Default, Debug, Clone, Copy)]
133#[serde(default)]
134#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
135pub struct Fields {
136 pub block: BlockFields,
137 pub transaction: TransactionFields,
138 pub log: LogFields,
139 pub trace: TraceFields,
140}
141
142impl Fields {
143 pub fn all() -> Self {
144 Self {
145 block: BlockFields::all(),
146 transaction: TransactionFields::all(),
147 log: LogFields::all(),
148 trace: TraceFields::all(),
149 }
150 }
151}
152
153#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
155#[serde(default)]
156#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
157#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
158pub struct BlockFields {
159 pub number: bool,
160 pub hash: bool,
161 pub parent_hash: bool,
162 pub nonce: bool,
163 pub sha3_uncles: bool,
164 pub logs_bloom: bool,
165 pub transactions_root: bool,
166 pub state_root: bool,
167 pub receipts_root: bool,
168 pub miner: bool,
169 pub difficulty: bool,
170 pub total_difficulty: bool,
171 pub extra_data: bool,
172 pub size: bool,
173 pub gas_limit: bool,
174 pub gas_used: bool,
175 pub timestamp: bool,
176 pub uncles: bool,
177 pub base_fee_per_gas: bool,
178 pub blob_gas_used: bool,
179 pub excess_blob_gas: bool,
180 pub parent_beacon_block_root: bool,
181 pub withdrawals_root: bool,
182 pub withdrawals: bool,
183 pub l1_block_number: bool,
184 pub send_count: bool,
185 pub send_root: bool,
186 pub mix_hash: bool,
187}
188
189impl BlockFields {
190 pub fn all() -> Self {
191 BlockFields {
192 number: true,
193 hash: true,
194 parent_hash: true,
195 nonce: true,
196 sha3_uncles: true,
197 logs_bloom: true,
198 transactions_root: true,
199 state_root: true,
200 receipts_root: true,
201 miner: true,
202 difficulty: true,
203 total_difficulty: true,
204 extra_data: true,
205 size: true,
206 gas_limit: true,
207 gas_used: true,
208 timestamp: true,
209 uncles: true,
210 base_fee_per_gas: true,
211 blob_gas_used: true,
212 excess_blob_gas: true,
213 parent_beacon_block_root: true,
214 withdrawals_root: true,
215 withdrawals: true,
216 l1_block_number: true,
217 send_count: true,
218 send_root: true,
219 mix_hash: true,
220 }
221 }
222}
223
224#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
226#[serde(default)]
227#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
228#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
229pub struct TransactionFields {
230 pub block_hash: bool,
231 pub block_number: bool,
232 #[serde(rename = "from")]
233 pub from_: bool,
234 pub gas: bool,
235 pub gas_price: bool,
236 pub hash: bool,
237 pub input: bool,
238 pub nonce: bool,
239 pub to: bool,
240 pub transaction_index: bool,
241 pub value: bool,
242 pub v: bool,
243 pub r: bool,
244 pub s: bool,
245 pub max_priority_fee_per_gas: bool,
246 pub max_fee_per_gas: bool,
247 pub chain_id: bool,
248 pub cumulative_gas_used: bool,
249 pub effective_gas_price: bool,
250 pub gas_used: bool,
251 pub contract_address: bool,
252 pub logs_bloom: bool,
253 #[serde(rename = "type")]
254 pub type_: bool,
255 pub root: bool,
256 pub status: bool,
257 pub sighash: bool,
258 pub y_parity: bool,
259 pub access_list: bool,
260 pub l1_fee: bool,
261 pub l1_gas_price: bool,
262 pub l1_fee_scalar: bool,
263 pub gas_used_for_l1: bool,
264 pub max_fee_per_blob_gas: bool,
265 pub blob_versioned_hashes: bool,
266 pub deposit_nonce: bool,
267 pub blob_gas_price: bool,
268 pub deposit_receipt_version: bool,
269 pub blob_gas_used: bool,
270 pub l1_base_fee_scalar: bool,
271 pub l1_blob_base_fee: bool,
272 pub l1_blob_base_fee_scalar: bool,
273 pub l1_block_number: bool,
274 pub mint: bool,
275 pub source_hash: bool,
276}
277
278impl TransactionFields {
279 pub fn all() -> Self {
280 TransactionFields {
281 block_hash: true,
282 block_number: true,
283 from_: true,
284 gas: true,
285 gas_price: true,
286 hash: true,
287 input: true,
288 nonce: true,
289 to: true,
290 transaction_index: true,
291 value: true,
292 v: true,
293 r: true,
294 s: true,
295 max_priority_fee_per_gas: true,
296 max_fee_per_gas: true,
297 chain_id: true,
298 cumulative_gas_used: true,
299 effective_gas_price: true,
300 gas_used: true,
301 contract_address: true,
302 logs_bloom: true,
303 type_: true,
304 root: true,
305 status: true,
306 sighash: true,
307 y_parity: true,
308 access_list: true,
309 l1_fee: true,
310 l1_gas_price: true,
311 l1_fee_scalar: true,
312 gas_used_for_l1: true,
313 max_fee_per_blob_gas: true,
314 blob_versioned_hashes: true,
315 deposit_nonce: true,
316 blob_gas_price: true,
317 deposit_receipt_version: true,
318 blob_gas_used: true,
319 l1_base_fee_scalar: true,
320 l1_blob_base_fee: true,
321 l1_blob_base_fee_scalar: true,
322 l1_block_number: true,
323 mint: true,
324 source_hash: true,
325 }
326 }
327}
328
329#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
331#[serde(default)]
332#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
333#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
334pub struct LogFields {
335 pub removed: bool,
336 pub log_index: bool,
337 pub transaction_index: bool,
338 pub transaction_hash: bool,
339 pub block_hash: bool,
340 pub block_number: bool,
341 pub address: bool,
342 pub data: bool,
343 pub topic0: bool,
344 pub topic1: bool,
345 pub topic2: bool,
346 pub topic3: bool,
347}
348
349impl LogFields {
350 pub fn all() -> Self {
351 LogFields {
352 removed: true,
353 log_index: true,
354 transaction_index: true,
355 transaction_hash: true,
356 block_hash: true,
357 block_number: true,
358 address: true,
359 data: true,
360 topic0: true,
361 topic1: true,
362 topic2: true,
363 topic3: true,
364 }
365 }
366}
367
368#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
370#[serde(default)]
371#[cfg_attr(feature = "pyo3", derive(pyo3::FromPyObject))]
372#[expect(clippy::struct_excessive_bools, reason = "field selection flags")]
373pub struct TraceFields {
374 #[serde(rename = "from")]
375 pub from_: bool,
376 pub to: bool,
377 pub call_type: bool,
378 pub gas: bool,
379 pub input: bool,
380 pub init: bool,
381 pub value: bool,
382 pub author: bool,
383 pub reward_type: bool,
384 pub block_hash: bool,
385 pub block_number: bool,
386 pub address: bool,
387 pub code: bool,
388 pub gas_used: bool,
389 pub output: bool,
390 pub subtraces: bool,
391 pub trace_address: bool,
392 pub transaction_hash: bool,
393 pub transaction_position: bool,
394 #[serde(rename = "type")]
395 pub type_: bool,
396 pub error: bool,
397 pub sighash: bool,
398 pub action_address: bool,
399 pub balance: bool,
400 pub refund_address: bool,
401}
402
403impl TraceFields {
404 pub fn all() -> Self {
405 TraceFields {
406 from_: true,
407 to: true,
408 call_type: true,
409 gas: true,
410 input: true,
411 init: true,
412 value: true,
413 author: true,
414 reward_type: true,
415 block_hash: true,
416 block_number: true,
417 address: true,
418 code: true,
419 gas_used: true,
420 output: true,
421 subtraces: true,
422 trace_address: true,
423 transaction_hash: true,
424 transaction_position: true,
425 type_: true,
426 error: true,
427 sighash: true,
428 action_address: true,
429 balance: true,
430 refund_address: true,
431 }
432 }
433}