nautilus_model/python/defi/
data.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Python bindings for DeFi data types.
17
18use std::{
19    collections::hash_map::DefaultHasher,
20    hash::{Hash, Hasher},
21    sync::Arc,
22};
23
24use nautilus_core::python::to_pyvalue_err;
25use pyo3::{basic::CompareOp, prelude::*};
26
27use crate::{
28    defi::{
29        Chain, Dex,
30        chain::Blockchain,
31        data::{
32            Block, PoolFeeCollect, PoolFlash, PoolLiquidityUpdate, PoolLiquidityUpdateType,
33            PoolSwap, Transaction,
34        },
35    },
36    identifiers::InstrumentId,
37};
38
39#[pymethods]
40impl Block {
41    #[getter]
42    #[pyo3(name = "chain")]
43    fn py_chain(&self) -> Option<Blockchain> {
44        self.chain
45    }
46
47    #[getter]
48    #[pyo3(name = "hash")]
49    fn py_hash(&self) -> &str {
50        &self.hash
51    }
52
53    #[getter]
54    #[pyo3(name = "number")]
55    fn py_number(&self) -> u64 {
56        self.number
57    }
58
59    #[getter]
60    #[pyo3(name = "parent_hash")]
61    fn py_parent_hash(&self) -> &str {
62        &self.parent_hash
63    }
64
65    #[getter]
66    #[pyo3(name = "miner")]
67    fn py_miner(&self) -> &str {
68        &self.miner
69    }
70
71    #[getter]
72    #[pyo3(name = "gas_limit")]
73    fn py_gas_limit(&self) -> u64 {
74        self.gas_limit
75    }
76
77    #[getter]
78    #[pyo3(name = "gas_used")]
79    fn py_gas_used(&self) -> u64 {
80        self.gas_used
81    }
82
83    #[getter]
84    #[pyo3(name = "base_fee_per_gas")]
85    fn py_base_fee_per_gas(&self) -> Option<String> {
86        self.base_fee_per_gas.map(|x| x.to_string())
87    }
88
89    #[getter]
90    #[pyo3(name = "blob_gas_used")]
91    fn py_blob_gas_used(&self) -> Option<String> {
92        self.blob_gas_used.map(|x| x.to_string())
93    }
94
95    #[getter]
96    #[pyo3(name = "excess_blob_gas")]
97    fn py_excess_blob_gas(&self) -> Option<String> {
98        self.excess_blob_gas.map(|x| x.to_string())
99    }
100
101    #[getter]
102    #[pyo3(name = "l1_gas_price")]
103    fn py_l1_gas_price(&self) -> Option<String> {
104        self.l1_gas_price.map(|x| x.to_string())
105    }
106
107    #[getter]
108    #[pyo3(name = "l1_gas_used")]
109    fn py_l1_gas_used(&self) -> Option<u64> {
110        self.l1_gas_used
111    }
112
113    #[getter]
114    #[pyo3(name = "l1_fee_scalar")]
115    fn py_l1_fee_scalar(&self) -> Option<u64> {
116        self.l1_fee_scalar
117    }
118
119    #[getter]
120    #[pyo3(name = "timestamp")]
121    fn py_timestamp(&self) -> u64 {
122        self.timestamp.as_u64()
123    }
124
125    fn __str__(&self) -> String {
126        self.to_string()
127    }
128
129    fn __repr__(&self) -> String {
130        format!("{self:?}")
131    }
132
133    fn __hash__(&self) -> u64 {
134        let mut hasher = DefaultHasher::new();
135        self.hash.hash(&mut hasher);
136        hasher.finish()
137    }
138}
139
140#[pymethods]
141impl PoolSwap {
142    #[new]
143    #[allow(clippy::too_many_arguments)]
144    fn py_new(
145        chain: Chain,
146        dex: Dex,
147        instrument_id: InstrumentId,
148        pool_identifier: String,
149        block: u64,
150        transaction_hash: String,
151        transaction_index: u32,
152        log_index: u32,
153        timestamp: u64,
154        sender: String,
155        receiver: String,
156        amount0: String,
157        amount1: String,
158        sqrt_price_x96: String,
159        liquidity: u128,
160        tick: i32,
161    ) -> PyResult<Self> {
162        let sender = sender.parse().map_err(to_pyvalue_err)?;
163        let receiver = receiver.parse().map_err(to_pyvalue_err)?;
164        let amount0 = amount0.parse().map_err(to_pyvalue_err)?;
165        let amount1 = amount1.parse().map_err(to_pyvalue_err)?;
166        let sqrt_price_x96 = sqrt_price_x96.parse().map_err(to_pyvalue_err)?;
167        let pool_identifier = pool_identifier.parse().map_err(to_pyvalue_err)?;
168        Ok(Self::new(
169            Arc::new(chain),
170            Arc::new(dex),
171            instrument_id,
172            pool_identifier,
173            block,
174            transaction_hash,
175            transaction_index,
176            log_index,
177            Some(timestamp.into()),
178            sender,
179            receiver,
180            amount0,
181            amount1,
182            sqrt_price_x96,
183            liquidity,
184            tick,
185        ))
186    }
187
188    fn __str__(&self) -> String {
189        self.to_string()
190    }
191
192    fn __repr__(&self) -> String {
193        format!("{self:?}")
194    }
195
196    fn __hash__(&self) -> u64 {
197        let mut hasher = DefaultHasher::new();
198        self.chain.chain_id.hash(&mut hasher);
199        self.transaction_hash.hash(&mut hasher);
200        self.log_index.hash(&mut hasher);
201        hasher.finish()
202    }
203
204    fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool {
205        match op {
206            CompareOp::Eq => self == other,
207            CompareOp::Ne => self != other,
208            _ => panic!("Unsupported comparison for PoolSwap"),
209        }
210    }
211
212    #[getter]
213    #[pyo3(name = "chain")]
214    fn py_chain(&self) -> PyResult<Chain> {
215        Ok(self.chain.as_ref().clone())
216    }
217
218    #[getter]
219    #[pyo3(name = "dex")]
220    fn py_dex(&self) -> PyResult<Dex> {
221        Ok(self.dex.as_ref().clone())
222    }
223
224    #[getter]
225    #[pyo3(name = "instrument_id")]
226    fn py_instrument_id(&self) -> InstrumentId {
227        self.instrument_id
228    }
229
230    #[getter]
231    #[pyo3(name = "pool_identifier")]
232    fn py_pool_identifier(&self) -> String {
233        self.pool_identifier.to_string()
234    }
235
236    #[getter]
237    #[pyo3(name = "block")]
238    fn py_block(&self) -> u64 {
239        self.block
240    }
241
242    #[getter]
243    #[pyo3(name = "transaction_hash")]
244    fn py_transaction_hash(&self) -> &str {
245        &self.transaction_hash
246    }
247
248    #[getter]
249    #[pyo3(name = "transaction_index")]
250    fn py_transaction_index(&self) -> u32 {
251        self.transaction_index
252    }
253
254    #[getter]
255    #[pyo3(name = "log_index")]
256    fn py_log_index(&self) -> u32 {
257        self.log_index
258    }
259
260    #[getter]
261    #[pyo3(name = "sender")]
262    fn py_sender(&self) -> String {
263        self.sender.to_string()
264    }
265
266    #[getter]
267    #[pyo3(name = "timestamp")]
268    fn py_timestamp(&self) -> Option<u64> {
269        self.timestamp.map(|x| x.as_u64())
270    }
271
272    #[getter]
273    #[pyo3(name = "ts_init")]
274    fn py_ts_init(&self) -> Option<u64> {
275        self.ts_init.map(|x| x.as_u64())
276    }
277}
278
279#[pymethods]
280impl PoolLiquidityUpdate {
281    #[new]
282    #[allow(clippy::too_many_arguments)]
283    fn py_new(
284        chain: Chain,
285        dex: Dex,
286        pool_identifier: String,
287        instrument_id: InstrumentId,
288        kind: PoolLiquidityUpdateType,
289        block: u64,
290        transaction_hash: String,
291        transaction_index: u32,
292        log_index: u32,
293        sender: Option<String>,
294        owner: String,
295        position_liquidity: String,
296        amount0: String,
297        amount1: String,
298        tick_lower: i32,
299        tick_upper: i32,
300        timestamp: u64,
301    ) -> PyResult<Self> {
302        let sender = sender
303            .map(|s| s.parse())
304            .transpose()
305            .map_err(to_pyvalue_err)?;
306        let owner = owner.parse().map_err(to_pyvalue_err)?;
307        let position_liquidity = position_liquidity.parse().map_err(to_pyvalue_err)?;
308        let amount0 = amount0.parse().map_err(to_pyvalue_err)?;
309        let amount1 = amount1.parse().map_err(to_pyvalue_err)?;
310        let pool_identifier = pool_identifier.parse().map_err(to_pyvalue_err)?;
311        Ok(Self::new(
312            Arc::new(chain),
313            Arc::new(dex),
314            instrument_id,
315            pool_identifier,
316            kind,
317            block,
318            transaction_hash,
319            transaction_index,
320            log_index,
321            sender,
322            owner,
323            position_liquidity,
324            amount0,
325            amount1,
326            tick_lower,
327            tick_upper,
328            Some(timestamp.into()),
329        ))
330    }
331
332    fn __str__(&self) -> String {
333        self.to_string()
334    }
335
336    fn __repr__(&self) -> String {
337        format!("{self:?}")
338    }
339
340    fn __hash__(&self) -> u64 {
341        let mut hasher = DefaultHasher::new();
342        self.chain.chain_id.hash(&mut hasher);
343        self.transaction_hash.hash(&mut hasher);
344        self.log_index.hash(&mut hasher);
345        hasher.finish()
346    }
347
348    fn __richcmp__(&self, other: &Self, op: pyo3::pyclass::CompareOp) -> bool {
349        match op {
350            CompareOp::Eq => self == other,
351            CompareOp::Ne => self != other,
352            _ => panic!("Unsupported comparison for PoolLiquidityUpdate"),
353        }
354    }
355
356    #[getter]
357    #[pyo3(name = "chain")]
358    fn py_chain(&self) -> PyResult<Chain> {
359        Ok(self.chain.as_ref().clone())
360    }
361
362    #[getter]
363    #[pyo3(name = "dex")]
364    fn py_dex(&self) -> PyResult<Dex> {
365        Ok(self.dex.as_ref().clone())
366    }
367
368    #[getter]
369    #[pyo3(name = "instrument_id")]
370    fn py_instrument_id(&self) -> InstrumentId {
371        self.instrument_id
372    }
373
374    #[getter]
375    #[pyo3(name = "pool_identifier")]
376    fn py_pool_identifier(&self) -> String {
377        self.pool_identifier.to_string()
378    }
379
380    #[getter]
381    #[pyo3(name = "kind")]
382    fn py_kind(&self) -> PoolLiquidityUpdateType {
383        self.kind
384    }
385
386    #[getter]
387    #[pyo3(name = "block")]
388    fn py_block(&self) -> u64 {
389        self.block
390    }
391
392    #[getter]
393    #[pyo3(name = "transaction_hash")]
394    fn py_transaction_hash(&self) -> &str {
395        &self.transaction_hash
396    }
397
398    #[getter]
399    #[pyo3(name = "transaction_index")]
400    fn py_transaction_index(&self) -> u32 {
401        self.transaction_index
402    }
403
404    #[getter]
405    #[pyo3(name = "log_index")]
406    fn py_log_index(&self) -> u32 {
407        self.log_index
408    }
409
410    #[getter]
411    #[pyo3(name = "sender")]
412    fn py_sender(&self) -> Option<String> {
413        self.sender.map(|s| s.to_string())
414    }
415
416    #[getter]
417    #[pyo3(name = "owner")]
418    fn py_owner(&self) -> String {
419        self.owner.to_string()
420    }
421
422    #[getter]
423    #[pyo3(name = "position_liquidity")]
424    fn py_position_liquidity(&self) -> String {
425        self.position_liquidity.to_string()
426    }
427
428    #[getter]
429    #[pyo3(name = "amount0")]
430    fn py_amount0(&self) -> String {
431        self.amount0.to_string()
432    }
433
434    #[getter]
435    #[pyo3(name = "amount1")]
436    fn py_amount1(&self) -> String {
437        self.amount1.to_string()
438    }
439
440    #[getter]
441    #[pyo3(name = "tick_lower")]
442    fn py_tick_lower(&self) -> i32 {
443        self.tick_lower
444    }
445
446    #[getter]
447    #[pyo3(name = "tick_upper")]
448    fn py_tick_upper(&self) -> i32 {
449        self.tick_upper
450    }
451
452    #[getter]
453    #[pyo3(name = "timestamp")]
454    fn py_timestamp(&self) -> Option<u64> {
455        self.timestamp.map(|x| x.as_u64())
456    }
457
458    #[getter]
459    #[pyo3(name = "ts_init")]
460    fn py_ts_init(&self) -> Option<u64> {
461        self.ts_init.map(|x| x.as_u64())
462    }
463}
464
465#[pymethods]
466impl PoolFeeCollect {
467    #[new]
468    #[allow(clippy::too_many_arguments)]
469    fn py_new(
470        chain: Chain,
471        dex: Dex,
472        pool_identifier: String,
473        instrument_id: InstrumentId,
474        block: u64,
475        transaction_hash: String,
476        transaction_index: u32,
477        log_index: u32,
478        owner: String,
479        amount0: String,
480        amount1: String,
481        tick_lower: i32,
482        tick_upper: i32,
483        timestamp: u64,
484    ) -> PyResult<Self> {
485        let owner = owner.parse().map_err(to_pyvalue_err)?;
486        let amount0 = amount0.parse().map_err(to_pyvalue_err)?;
487        let amount1 = amount1.parse().map_err(to_pyvalue_err)?;
488        let pool_identifier = pool_identifier.parse().map_err(to_pyvalue_err)?;
489        Ok(Self::new(
490            Arc::new(chain),
491            Arc::new(dex),
492            instrument_id,
493            pool_identifier,
494            block,
495            transaction_hash,
496            transaction_index,
497            log_index,
498            owner,
499            amount0,
500            amount1,
501            tick_lower,
502            tick_upper,
503            Some(timestamp.into()),
504        ))
505    }
506
507    fn __str__(&self) -> String {
508        self.to_string()
509    }
510
511    fn __repr__(&self) -> String {
512        format!("{self:?}")
513    }
514
515    fn __hash__(&self) -> u64 {
516        let mut hasher = DefaultHasher::new();
517        self.chain.chain_id.hash(&mut hasher);
518        self.transaction_hash.hash(&mut hasher);
519        self.log_index.hash(&mut hasher);
520        hasher.finish()
521    }
522
523    fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool {
524        match op {
525            CompareOp::Eq => self == other,
526            CompareOp::Ne => self != other,
527            _ => panic!("Unsupported comparison for PoolFeeCollect"),
528        }
529    }
530
531    #[getter]
532    #[pyo3(name = "chain")]
533    fn py_chain(&self) -> PyResult<Chain> {
534        Ok(self.chain.as_ref().clone())
535    }
536
537    #[getter]
538    #[pyo3(name = "dex")]
539    fn py_dex(&self) -> PyResult<Dex> {
540        Ok(self.dex.as_ref().clone())
541    }
542
543    #[getter]
544    #[pyo3(name = "instrument_id")]
545    fn py_instrument_id(&self) -> InstrumentId {
546        self.instrument_id
547    }
548
549    #[getter]
550    #[pyo3(name = "pool_identifier")]
551    fn py_pool_identifier(&self) -> String {
552        self.pool_identifier.to_string()
553    }
554
555    #[getter]
556    #[pyo3(name = "block")]
557    fn py_block(&self) -> u64 {
558        self.block
559    }
560
561    #[getter]
562    #[pyo3(name = "transaction_hash")]
563    fn py_transaction_hash(&self) -> &str {
564        &self.transaction_hash
565    }
566
567    #[getter]
568    #[pyo3(name = "transaction_index")]
569    fn py_transaction_index(&self) -> u32 {
570        self.transaction_index
571    }
572
573    #[getter]
574    #[pyo3(name = "log_index")]
575    fn py_log_index(&self) -> u32 {
576        self.log_index
577    }
578
579    #[getter]
580    #[pyo3(name = "owner")]
581    fn py_owner(&self) -> String {
582        self.owner.to_string()
583    }
584
585    #[getter]
586    #[pyo3(name = "amount0")]
587    fn py_amount0(&self) -> String {
588        self.amount0.to_string()
589    }
590
591    #[getter]
592    #[pyo3(name = "amount1")]
593    fn py_amount1(&self) -> String {
594        self.amount1.to_string()
595    }
596
597    #[getter]
598    #[pyo3(name = "tick_lower")]
599    fn py_tick_lower(&self) -> i32 {
600        self.tick_lower
601    }
602
603    #[getter]
604    #[pyo3(name = "tick_upper")]
605    fn py_tick_upper(&self) -> i32 {
606        self.tick_upper
607    }
608
609    #[getter]
610    #[pyo3(name = "timestamp")]
611    fn py_timestamp(&self) -> Option<u64> {
612        self.timestamp.map(|x| x.as_u64())
613    }
614
615    #[getter]
616    #[pyo3(name = "ts_init")]
617    fn py_ts_init(&self) -> Option<u64> {
618        self.ts_init.map(|x| x.as_u64())
619    }
620}
621
622#[pymethods]
623impl PoolFlash {
624    #[new]
625    #[allow(clippy::too_many_arguments)]
626    fn py_new(
627        chain: Chain,
628        dex: Dex,
629        pool_identifier: String,
630        instrument_id: InstrumentId,
631        block: u64,
632        transaction_hash: String,
633        transaction_index: u32,
634        log_index: u32,
635        sender: String,
636        recipient: String,
637        amount0: String,
638        amount1: String,
639        paid0: String,
640        paid1: String,
641        timestamp: u64,
642    ) -> PyResult<Self> {
643        let sender = sender.parse().map_err(to_pyvalue_err)?;
644        let recipient = recipient.parse().map_err(to_pyvalue_err)?;
645        let amount0 = amount0.parse().map_err(to_pyvalue_err)?;
646        let amount1 = amount1.parse().map_err(to_pyvalue_err)?;
647        let paid0 = paid0.parse().map_err(to_pyvalue_err)?;
648        let paid1 = paid1.parse().map_err(to_pyvalue_err)?;
649        let pool_identifier = pool_identifier.parse().map_err(to_pyvalue_err)?;
650        Ok(Self::new(
651            Arc::new(chain),
652            Arc::new(dex),
653            instrument_id,
654            pool_identifier,
655            block,
656            transaction_hash,
657            transaction_index,
658            log_index,
659            Some(timestamp.into()),
660            sender,
661            recipient,
662            amount0,
663            amount1,
664            paid0,
665            paid1,
666        ))
667    }
668
669    fn __str__(&self) -> String {
670        self.to_string()
671    }
672
673    fn __repr__(&self) -> String {
674        format!("{self:?}")
675    }
676
677    fn __hash__(&self) -> u64 {
678        let mut hasher = DefaultHasher::new();
679        self.chain.chain_id.hash(&mut hasher);
680        self.transaction_hash.hash(&mut hasher);
681        self.log_index.hash(&mut hasher);
682        hasher.finish()
683    }
684
685    fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool {
686        match op {
687            CompareOp::Eq => self == other,
688            CompareOp::Ne => self != other,
689            _ => panic!("Unsupported comparison for PoolFlash"),
690        }
691    }
692
693    #[getter]
694    #[pyo3(name = "chain")]
695    fn py_chain(&self) -> PyResult<Chain> {
696        Ok(self.chain.as_ref().clone())
697    }
698
699    #[getter]
700    #[pyo3(name = "dex")]
701    fn py_dex(&self) -> PyResult<Dex> {
702        Ok(self.dex.as_ref().clone())
703    }
704
705    #[getter]
706    #[pyo3(name = "instrument_id")]
707    fn py_instrument_id(&self) -> InstrumentId {
708        self.instrument_id
709    }
710
711    #[getter]
712    #[pyo3(name = "pool_identifier")]
713    fn py_pool_identifier(&self) -> String {
714        self.pool_identifier.to_string()
715    }
716
717    #[getter]
718    #[pyo3(name = "block")]
719    fn py_block(&self) -> u64 {
720        self.block
721    }
722
723    #[getter]
724    #[pyo3(name = "transaction_hash")]
725    fn py_transaction_hash(&self) -> &str {
726        &self.transaction_hash
727    }
728
729    #[getter]
730    #[pyo3(name = "transaction_index")]
731    fn py_transaction_index(&self) -> u32 {
732        self.transaction_index
733    }
734
735    #[getter]
736    #[pyo3(name = "log_index")]
737    fn py_log_index(&self) -> u32 {
738        self.log_index
739    }
740
741    #[getter]
742    #[pyo3(name = "sender")]
743    fn py_sender(&self) -> String {
744        self.sender.to_string()
745    }
746
747    #[getter]
748    #[pyo3(name = "recipient")]
749    fn py_recipient(&self) -> String {
750        self.recipient.to_string()
751    }
752
753    #[getter]
754    #[pyo3(name = "amount0")]
755    fn py_amount0(&self) -> String {
756        self.amount0.to_string()
757    }
758
759    #[getter]
760    #[pyo3(name = "amount1")]
761    fn py_amount1(&self) -> String {
762        self.amount1.to_string()
763    }
764
765    #[getter]
766    #[pyo3(name = "paid0")]
767    fn py_paid0(&self) -> String {
768        self.paid0.to_string()
769    }
770
771    #[getter]
772    #[pyo3(name = "paid1")]
773    fn py_paid1(&self) -> String {
774        self.paid1.to_string()
775    }
776
777    #[getter]
778    #[pyo3(name = "timestamp")]
779    fn py_timestamp(&self) -> Option<u64> {
780        self.ts_event.map(|x| x.as_u64())
781    }
782}
783
784#[pymethods]
785impl Transaction {
786    #[new]
787    #[allow(clippy::too_many_arguments)]
788    fn py_new(
789        chain: Chain,
790        hash: String,
791        block_hash: String,
792        block_number: u64,
793        from: String,
794        to: String,
795        gas: String,
796        gas_price: String,
797        transaction_index: u64,
798        value: String,
799    ) -> PyResult<Self> {
800        let from = from.parse().map_err(to_pyvalue_err)?;
801        let to = to.parse().map_err(to_pyvalue_err)?;
802        let gas = gas.parse().map_err(to_pyvalue_err)?;
803        let gas_price = gas_price.parse().map_err(to_pyvalue_err)?;
804        let value = value.parse().map_err(to_pyvalue_err)?;
805        Ok(Self::new(
806            chain,
807            hash,
808            block_hash,
809            block_number,
810            from,
811            to,
812            gas,
813            gas_price,
814            transaction_index,
815            value,
816        ))
817    }
818
819    fn __str__(&self) -> String {
820        format!(
821            "Transaction(chain={}, hash={}, block_number={}, from={}, to={}, value={})",
822            self.chain.name, self.hash, self.block_number, self.from, self.to, self.value
823        )
824    }
825
826    fn __repr__(&self) -> String {
827        format!("{self:?}")
828    }
829
830    fn __hash__(&self) -> u64 {
831        let mut hasher = DefaultHasher::new();
832        self.hash.hash(&mut hasher);
833        hasher.finish()
834    }
835
836    fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool {
837        match op {
838            CompareOp::Eq => self.hash == other.hash,
839            CompareOp::Ne => self.hash != other.hash,
840            _ => panic!("Unsupported comparison for Transaction"),
841        }
842    }
843
844    #[getter]
845    #[pyo3(name = "chain")]
846    fn py_chain(&self) -> Chain {
847        self.chain.clone()
848    }
849
850    #[getter]
851    #[pyo3(name = "hash")]
852    fn py_hash(&self) -> &str {
853        &self.hash
854    }
855
856    #[getter]
857    #[pyo3(name = "block_hash")]
858    fn py_block_hash(&self) -> &str {
859        &self.block_hash
860    }
861
862    #[getter]
863    #[pyo3(name = "block_number")]
864    fn py_block_number(&self) -> u64 {
865        self.block_number
866    }
867
868    #[getter]
869    #[pyo3(name = "from")]
870    fn py_from(&self) -> String {
871        self.from.to_string()
872    }
873
874    #[getter]
875    #[pyo3(name = "to")]
876    fn py_to(&self) -> String {
877        self.to.to_string()
878    }
879
880    #[getter]
881    #[pyo3(name = "value")]
882    fn py_value(&self) -> String {
883        self.value.to_string()
884    }
885
886    #[getter]
887    #[pyo3(name = "transaction_index")]
888    fn py_transaction_index(&self) -> u64 {
889        self.transaction_index
890    }
891
892    #[getter]
893    #[pyo3(name = "gas")]
894    fn py_gas(&self) -> String {
895        self.gas.to_string()
896    }
897
898    #[getter]
899    #[pyo3(name = "gas_price")]
900    fn py_gas_price(&self) -> String {
901        self.gas_price.to_string()
902    }
903}