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