1#![allow(missing_docs)]
19
20use super::{
21 Byte, Bytes, TYPE_EIP1559, TYPE_EIP2930, TYPE_EIP4844, TYPE_EIP7702, TYPE_LEGACY, TypeEip1559,
22 TypeEip2930, TypeEip4844, TypeEip7702, TypeLegacy,
23};
24use alloc::vec::Vec;
25use codec::{Decode, DecodeWithMemTracking, Encode};
26use derive_more::{From, TryInto};
27use ethereum_types::*;
28use pallet_revive_types::runtime_api::*;
29use scale_info::TypeInfo;
30
31#[derive(Debug, Default, Clone, Eq, PartialEq)]
33pub struct GenericTransaction {
34 pub access_list: Option<AccessList>,
37 pub authorization_list: Vec<AuthorizationListEntry>,
40 pub blob_versioned_hashes: Vec<H256>,
43 pub blobs: Vec<Bytes>,
46 pub chain_id: Option<U256>,
49 pub from: Option<Address>,
51 pub gas: Option<U256>,
53 pub gas_price: Option<U256>,
56 pub input: InputOrData,
58 pub max_fee_per_blob_gas: Option<U256>,
61 pub max_fee_per_gas: Option<U256>,
65 pub max_priority_fee_per_gas: Option<U256>,
68 pub nonce: Option<U256>,
70 pub to: Option<Address>,
72 pub r#type: Option<Byte>,
74 pub value: Option<U256>,
76}
77
78impl GenericTransaction {
79 pub fn from_signed(tx: TransactionSigned, base_gas_price: U256, from: Option<H160>) -> Self {
81 Self::from_unsigned(tx.into(), base_gas_price, from)
82 }
83
84 pub fn has_simple_transfer_fields(&self) -> bool {
88 self.input.is_empty() &&
89 self.access_list.as_ref().is_none_or(|list| list.is_empty()) &&
90 self.authorization_list.is_empty() &&
91 self.blob_versioned_hashes.is_empty() &&
92 self.blobs.is_empty() &&
93 self.max_fee_per_blob_gas.is_none()
94 }
95
96 pub fn effective_gas_price(&self, base_gas_price: U256) -> Option<U256> {
98 let effective_gas_price = if let Some(prio_price) = self.max_priority_fee_per_gas {
99 let max_price = self.max_fee_per_gas?;
100 Some(max_price.min(base_gas_price.saturating_add(prio_price)))
101 } else {
102 self.gas_price
103 };
104
105 effective_gas_price.map(|e| e.min(base_gas_price))
108 }
109
110 pub fn from_unsigned(
112 tx: TransactionUnsigned,
113 base_gas_price: U256,
114 from: Option<H160>,
115 ) -> Self {
116 use TransactionUnsigned::*;
117 let mut tx = match tx {
118 TransactionLegacyUnsigned(tx) => GenericTransaction {
119 from,
120 r#type: Some(tx.r#type.as_byte()),
121 chain_id: tx.chain_id,
122 input: tx.input.into(),
123 nonce: Some(tx.nonce),
124 value: Some(tx.value),
125 to: tx.to,
126 gas: Some(tx.gas),
127 gas_price: Some(tx.gas_price),
128 ..Default::default()
129 },
130 Transaction4844Unsigned(tx) => GenericTransaction {
131 from,
132 r#type: Some(tx.r#type.as_byte()),
133 chain_id: Some(tx.chain_id),
134 input: tx.input.into(),
135 nonce: Some(tx.nonce),
136 value: Some(tx.value),
137 to: Some(tx.to),
138 gas: Some(tx.gas),
139 access_list: Some(tx.access_list),
140 blob_versioned_hashes: tx.blob_versioned_hashes,
141 max_fee_per_blob_gas: Some(tx.max_fee_per_blob_gas),
142 max_fee_per_gas: Some(tx.max_fee_per_gas),
143 max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas),
144 ..Default::default()
145 },
146 Transaction1559Unsigned(tx) => GenericTransaction {
147 from,
148 r#type: Some(tx.r#type.as_byte()),
149 chain_id: Some(tx.chain_id),
150 input: tx.input.into(),
151 nonce: Some(tx.nonce),
152 value: Some(tx.value),
153 to: tx.to,
154 gas: Some(tx.gas),
155 access_list: Some(tx.access_list),
156 max_fee_per_gas: Some(tx.max_fee_per_gas),
157 max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas),
158 ..Default::default()
159 },
160 Transaction2930Unsigned(tx) => GenericTransaction {
161 from,
162 r#type: Some(tx.r#type.as_byte()),
163 chain_id: Some(tx.chain_id),
164 input: tx.input.into(),
165 nonce: Some(tx.nonce),
166 value: Some(tx.value),
167 to: tx.to,
168 gas: Some(tx.gas),
169 gas_price: Some(tx.gas_price),
170 access_list: Some(tx.access_list),
171 ..Default::default()
172 },
173 Transaction7702Unsigned(tx) => GenericTransaction {
174 from,
175 r#type: Some(tx.r#type.as_byte()),
176 chain_id: Some(tx.chain_id),
177 input: tx.input.into(),
178 nonce: Some(tx.nonce),
179 value: Some(tx.value),
180 to: Some(tx.to),
181 gas: Some(tx.gas),
182 access_list: Some(tx.access_list),
183 authorization_list: tx.authorization_list,
184 max_fee_per_gas: Some(tx.max_fee_per_gas),
185 max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas),
186 ..Default::default()
187 },
188 };
189 tx.gas_price = tx.effective_gas_price(base_gas_price);
190 tx
191 }
192
193 pub fn try_into_unsigned(self) -> Result<TransactionUnsigned, ()> {
195 match self.r#type.unwrap_or_default().0 {
196 TYPE_LEGACY => Ok(TransactionLegacyUnsigned {
197 r#type: TypeLegacy {},
198 chain_id: self.chain_id,
199 input: self.input.to_bytes(),
200 nonce: self.nonce.unwrap_or_default(),
201 value: self.value.unwrap_or_default(),
202 to: self.to,
203 gas: self.gas.unwrap_or_default(),
204 gas_price: self.gas_price.unwrap_or_default(),
205 }
206 .into()),
207 TYPE_EIP1559 => Ok(Transaction1559Unsigned {
208 r#type: TypeEip1559 {},
209 chain_id: self.chain_id.unwrap_or_default(),
210 input: self.input.to_bytes(),
211 nonce: self.nonce.unwrap_or_default(),
212 value: self.value.unwrap_or_default(),
213 to: self.to,
214 gas: self.gas.unwrap_or_default(),
215 gas_price: self.max_fee_per_gas.unwrap_or_default(),
216 access_list: self.access_list.unwrap_or_default(),
217 max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(),
218 max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(),
219 }
220 .into()),
221 TYPE_EIP2930 => Ok(Transaction2930Unsigned {
222 r#type: TypeEip2930 {},
223 chain_id: self.chain_id.unwrap_or_default(),
224 input: self.input.to_bytes(),
225 nonce: self.nonce.unwrap_or_default(),
226 value: self.value.unwrap_or_default(),
227 to: self.to,
228 gas: self.gas.unwrap_or_default(),
229 gas_price: self.gas_price.unwrap_or_default(),
230 access_list: self.access_list.unwrap_or_default(),
231 }
232 .into()),
233 TYPE_EIP4844 => Ok(Transaction4844Unsigned {
234 r#type: TypeEip4844 {},
235 chain_id: self.chain_id.unwrap_or_default(),
236 input: self.input.to_bytes(),
237 nonce: self.nonce.unwrap_or_default(),
238 value: self.value.unwrap_or_default(),
239 to: self.to.unwrap_or_default(),
240 gas: self.gas.unwrap_or_default(),
241 max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(),
242 max_fee_per_blob_gas: self.max_fee_per_blob_gas.unwrap_or_default(),
243 max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(),
244 access_list: self.access_list.unwrap_or_default(),
245 blob_versioned_hashes: self.blob_versioned_hashes,
246 }
247 .into()),
248 TYPE_EIP7702 => Ok(Transaction7702Unsigned {
249 r#type: TypeEip7702 {},
250 chain_id: self.chain_id.unwrap_or_default(),
251 input: self.input.to_bytes(),
252 nonce: self.nonce.unwrap_or_default(),
253 value: self.value.unwrap_or_default(),
254 to: self.to.unwrap_or_default(),
255 gas: self.gas.unwrap_or_default(),
256 max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(),
257 max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(),
258 access_list: self.access_list.unwrap_or_default(),
259 authorization_list: self.authorization_list,
260 }
261 .into()),
262 _ => Err(()),
263 }
264 }
265}
266
267impl From<GenericTransactionV1> for GenericTransaction {
268 fn from(value: GenericTransactionV1) -> Self {
269 Self {
270 access_list: value.access_list.map(|list| list.into_iter().map(Into::into).collect()),
271 authorization_list: value.authorization_list.into_iter().map(Into::into).collect(),
272 blob_versioned_hashes: value.blob_versioned_hashes,
273 blobs: value.blobs,
274 chain_id: value.chain_id,
275 from: value.from,
276 gas: value.gas,
277 gas_price: value.gas_price,
278 input: value.input.into(),
279 max_fee_per_blob_gas: value.max_fee_per_blob_gas,
280 max_fee_per_gas: value.max_fee_per_gas,
281 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
282 nonce: value.nonce,
283 to: value.to,
284 r#type: value.r#type,
285 value: value.value,
286 }
287 }
288}
289
290impl From<GenericTransaction> for GenericTransactionV1 {
291 fn from(value: GenericTransaction) -> Self {
292 Self {
293 access_list: value.access_list.map(|list| list.into_iter().map(Into::into).collect()),
294 authorization_list: value.authorization_list.into_iter().map(Into::into).collect(),
295 blob_versioned_hashes: value.blob_versioned_hashes,
296 blobs: value.blobs,
297 chain_id: value.chain_id,
298 from: value.from,
299 gas: value.gas,
300 gas_price: value.gas_price,
301 input: value.input.into(),
302 max_fee_per_blob_gas: value.max_fee_per_blob_gas,
303 max_fee_per_gas: value.max_fee_per_gas,
304 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
305 nonce: value.nonce,
306 to: value.to,
307 r#type: value.r#type,
308 value: value.value,
309 }
310 }
311}
312
313#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode)]
315pub struct TransactionInfo {
316 pub block_hash: H256,
318 pub block_number: U256,
320 pub from: Address,
322 pub hash: H256,
324 pub transaction_index: U256,
326 pub transaction_signed: TransactionSigned,
327}
328
329impl From<TransactionInfo> for TransactionInfoV1 {
330 fn from(value: TransactionInfo) -> Self {
331 Self {
332 block_hash: value.block_hash,
333 block_number: value.block_number,
334 from: value.from,
335 hash: value.hash,
336 transaction_index: value.transaction_index,
337 transaction_signed: value.transaction_signed.into(),
338 }
339 }
340}
341
342#[derive(
343 Debug, Clone, From, TryInto, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking,
344)]
345pub enum TransactionSigned {
346 Transaction7702Signed(Transaction7702Signed),
347 Transaction4844Signed(Transaction4844Signed),
348 Transaction1559Signed(Transaction1559Signed),
349 Transaction2930Signed(Transaction2930Signed),
350 TransactionLegacySigned(TransactionLegacySigned),
351}
352
353impl Default for TransactionSigned {
354 fn default() -> Self {
355 TransactionSigned::TransactionLegacySigned(Default::default())
356 }
357}
358
359impl From<TransactionSigned> for TransactionSignedV1 {
360 fn from(value: TransactionSigned) -> Self {
361 match value {
362 TransactionSigned::Transaction7702Signed(tx) => Self::Transaction7702Signed(tx.into()),
363 TransactionSigned::Transaction4844Signed(tx) => Self::Transaction4844Signed(tx.into()),
364 TransactionSigned::Transaction1559Signed(tx) => Self::Transaction1559Signed(tx.into()),
365 TransactionSigned::Transaction2930Signed(tx) => Self::Transaction2930Signed(tx.into()),
366 TransactionSigned::TransactionLegacySigned(tx) => {
367 Self::TransactionLegacySigned(tx.into())
368 },
369 }
370 }
371}
372
373#[derive(Debug, Clone, From, TryInto, Eq, PartialEq)]
374pub enum TransactionUnsigned {
375 Transaction7702Unsigned(Transaction7702Unsigned),
376 Transaction4844Unsigned(Transaction4844Unsigned),
377 Transaction1559Unsigned(Transaction1559Unsigned),
378 Transaction2930Unsigned(Transaction2930Unsigned),
379 TransactionLegacyUnsigned(TransactionLegacyUnsigned),
380}
381
382impl Default for TransactionUnsigned {
383 fn default() -> Self {
384 TransactionUnsigned::TransactionLegacyUnsigned(Default::default())
385 }
386}
387
388impl From<TransactionSigned> for TransactionUnsigned {
389 fn from(tx: TransactionSigned) -> Self {
390 use TransactionSigned::*;
391 match tx {
392 Transaction7702Signed(tx) => tx.transaction_7702_unsigned.into(),
393 Transaction4844Signed(tx) => tx.transaction_4844_unsigned.into(),
394 Transaction1559Signed(tx) => tx.transaction_1559_unsigned.into(),
395 Transaction2930Signed(tx) => tx.transaction_2930_unsigned.into(),
396 TransactionLegacySigned(tx) => tx.transaction_legacy_unsigned.into(),
397 }
398 }
399}
400
401#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
403pub struct Transaction1559Unsigned {
404 pub access_list: AccessList,
407 pub chain_id: U256,
410 pub gas: U256,
412 pub gas_price: U256,
417 pub input: Bytes,
419 pub max_fee_per_gas: U256,
423 pub max_priority_fee_per_gas: U256,
426 pub nonce: U256,
428 pub to: Option<Address>,
430 pub r#type: TypeEip1559,
432 pub value: U256,
434}
435
436impl From<Transaction1559Unsigned> for Transaction1559UnsignedV1 {
437 fn from(value: Transaction1559Unsigned) -> Self {
438 Self {
439 access_list: value.access_list.into_iter().map(Into::into).collect(),
440 chain_id: value.chain_id,
441 gas: value.gas,
442 gas_price: value.gas_price,
443 input: value.input,
444 max_fee_per_gas: value.max_fee_per_gas,
445 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
446 nonce: value.nonce,
447 to: value.to,
448 r#type: value.r#type,
449 value: value.value,
450 }
451 }
452}
453
454#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
456pub struct Transaction2930Unsigned {
457 pub access_list: AccessList,
460 pub chain_id: U256,
463 pub gas: U256,
465 pub gas_price: U256,
468 pub input: Bytes,
470 pub nonce: U256,
472 pub to: Option<Address>,
474 pub r#type: TypeEip2930,
476 pub value: U256,
478}
479
480impl From<Transaction2930Unsigned> for Transaction2930UnsignedV1 {
481 fn from(value: Transaction2930Unsigned) -> Self {
482 Self {
483 access_list: value.access_list.into_iter().map(Into::into).collect(),
484 chain_id: value.chain_id,
485 gas: value.gas,
486 gas_price: value.gas_price,
487 input: value.input,
488 nonce: value.nonce,
489 to: value.to,
490 r#type: value.r#type,
491 value: value.value,
492 }
493 }
494}
495
496#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
498pub struct Transaction4844Unsigned {
499 pub access_list: AccessList,
502 pub blob_versioned_hashes: Vec<H256>,
505 pub chain_id: U256,
508 pub gas: U256,
510 pub input: Bytes,
512 pub max_fee_per_blob_gas: U256,
515 pub max_fee_per_gas: U256,
519 pub max_priority_fee_per_gas: U256,
522 pub nonce: U256,
524 pub to: Address,
526 pub r#type: TypeEip4844,
528 pub value: U256,
530}
531
532impl From<Transaction4844Unsigned> for Transaction4844UnsignedV1 {
533 fn from(value: Transaction4844Unsigned) -> Self {
534 Self {
535 access_list: value.access_list.into_iter().map(Into::into).collect(),
536 blob_versioned_hashes: value.blob_versioned_hashes,
537 chain_id: value.chain_id,
538 gas: value.gas,
539 input: value.input,
540 max_fee_per_blob_gas: value.max_fee_per_blob_gas,
541 max_fee_per_gas: value.max_fee_per_gas,
542 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
543 nonce: value.nonce,
544 to: value.to,
545 r#type: value.r#type,
546 value: value.value,
547 }
548 }
549}
550
551#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
553pub struct TransactionLegacyUnsigned {
554 pub chain_id: Option<U256>,
557 pub gas: U256,
559 pub gas_price: U256,
562 pub input: Bytes,
564 pub nonce: U256,
566 pub to: Option<Address>,
568 pub r#type: TypeLegacy,
570 pub value: U256,
572}
573
574impl From<TransactionLegacyUnsigned> for TransactionLegacyUnsignedV1 {
575 fn from(value: TransactionLegacyUnsigned) -> Self {
576 Self {
577 chain_id: value.chain_id,
578 gas: value.gas,
579 gas_price: value.gas_price,
580 input: value.input,
581 nonce: value.nonce,
582 to: value.to,
583 r#type: value.r#type,
584 value: value.value,
585 }
586 }
587}
588
589#[derive(
591 Debug, Clone, Default, From, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking,
592)]
593pub struct Transaction7702Unsigned {
594 pub access_list: AccessList,
597 pub authorization_list: Vec<AuthorizationListEntry>,
600 pub chain_id: U256,
603 pub gas: U256,
605 pub input: Bytes,
607 pub max_fee_per_gas: U256,
611 pub max_priority_fee_per_gas: U256,
614 pub nonce: U256,
616 pub to: Address,
622 pub r#type: TypeEip7702,
624 pub value: U256,
626}
627
628impl From<Transaction7702Unsigned> for Transaction7702UnsignedV1 {
629 fn from(value: Transaction7702Unsigned) -> Self {
630 Self {
631 access_list: value.access_list.into_iter().map(Into::into).collect(),
632 authorization_list: value.authorization_list.into_iter().map(Into::into).collect(),
633 chain_id: value.chain_id,
634 gas: value.gas,
635 input: value.input,
636 max_fee_per_gas: value.max_fee_per_gas,
637 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
638 nonce: value.nonce,
639 to: value.to,
640 r#type: value.r#type,
641 value: value.value,
642 }
643 }
644}
645
646#[derive(Debug, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
648pub struct Transaction7702Signed {
649 pub transaction_7702_unsigned: Transaction7702Unsigned,
650 pub r: U256,
652 pub s: U256,
654 pub v: Option<U256>,
658 pub y_parity: U256,
661}
662
663impl From<Transaction7702Signed> for Transaction7702SignedV1 {
664 fn from(value: Transaction7702Signed) -> Self {
665 Self {
666 transaction_7702_unsigned: value.transaction_7702_unsigned.into(),
667 r: value.r,
668 s: value.s,
669 v: value.v,
670 y_parity: value.y_parity,
671 }
672 }
673}
674
675#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
677pub struct Transaction1559Signed {
678 pub transaction_1559_unsigned: Transaction1559Unsigned,
679 pub r: U256,
681 pub s: U256,
683 pub v: Option<U256>,
687 pub y_parity: U256,
690}
691
692impl From<Transaction1559Signed> for Transaction1559SignedV1 {
693 fn from(value: Transaction1559Signed) -> Self {
694 Self {
695 transaction_1559_unsigned: value.transaction_1559_unsigned.into(),
696 r: value.r,
697 s: value.s,
698 v: value.v,
699 y_parity: value.y_parity,
700 }
701 }
702}
703
704#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
706pub struct Transaction2930Signed {
707 pub transaction_2930_unsigned: Transaction2930Unsigned,
708 pub r: U256,
710 pub s: U256,
712 pub v: Option<U256>,
716 pub y_parity: U256,
719}
720
721impl From<Transaction2930Signed> for Transaction2930SignedV1 {
722 fn from(value: Transaction2930Signed) -> Self {
723 Self {
724 transaction_2930_unsigned: value.transaction_2930_unsigned.into(),
725 r: value.r,
726 s: value.s,
727 v: value.v,
728 y_parity: value.y_parity,
729 }
730 }
731}
732
733#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
735pub struct Transaction4844Signed {
736 pub transaction_4844_unsigned: Transaction4844Unsigned,
737 pub r: U256,
739 pub s: U256,
741 pub y_parity: U256,
744}
745
746impl From<Transaction4844Signed> for Transaction4844SignedV1 {
747 fn from(value: Transaction4844Signed) -> Self {
748 Self {
749 transaction_4844_unsigned: value.transaction_4844_unsigned.into(),
750 r: value.r,
751 s: value.s,
752 y_parity: value.y_parity,
753 }
754 }
755}
756
757#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
759pub struct TransactionLegacySigned {
760 pub transaction_legacy_unsigned: TransactionLegacyUnsigned,
761 pub r: U256,
763 pub s: U256,
765 pub v: U256,
767}
768
769impl From<TransactionLegacySigned> for TransactionLegacySignedV1 {
770 fn from(value: TransactionLegacySigned) -> Self {
771 Self {
772 transaction_legacy_unsigned: value.transaction_legacy_unsigned.into(),
773 r: value.r,
774 s: value.s,
775 v: value.v,
776 }
777 }
778}
779
780pub type AccessList = Vec<AccessListEntry>;
782
783#[derive(Debug, Default, Clone, Encode, Decode, TypeInfo, Eq, PartialEq, DecodeWithMemTracking)]
785pub struct AccessListEntry {
786 pub address: Address,
787 pub storage_keys: Vec<H256>,
788}
789
790impl From<AccessListEntryV1> for AccessListEntry {
791 fn from(value: AccessListEntryV1) -> Self {
792 Self { address: value.address, storage_keys: value.storage_keys }
793 }
794}
795
796impl From<AccessListEntry> for AccessListEntryV1 {
797 fn from(value: AccessListEntry) -> Self {
798 Self { address: value.address, storage_keys: value.storage_keys }
799 }
800}
801
802#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
804pub struct AuthorizationListEntry {
805 pub chain_id: U256,
807 pub address: Address,
809 pub nonce: U256,
811 pub y_parity: U256,
813 pub r: U256,
815 pub s: U256,
817}
818
819impl From<AuthorizationListEntryV1> for AuthorizationListEntry {
820 fn from(value: AuthorizationListEntryV1) -> Self {
821 Self {
822 chain_id: value.chain_id,
823 address: value.address,
824 nonce: value.nonce,
825 y_parity: value.y_parity,
826 r: value.r,
827 s: value.s,
828 }
829 }
830}
831
832impl From<AuthorizationListEntry> for AuthorizationListEntryV1 {
833 fn from(value: AuthorizationListEntry) -> Self {
834 Self {
835 chain_id: value.chain_id,
836 address: value.address,
837 nonce: value.nonce,
838 y_parity: value.y_parity,
839 r: value.r,
840 s: value.s,
841 }
842 }
843}
844
845#[derive(Debug, Clone, From, TryInto, Eq, PartialEq, TypeInfo, Encode, Decode)]
846pub enum HashesOrTransactionInfos {
847 Hashes(Vec<H256>),
849 TransactionInfos(Vec<TransactionInfo>),
851}
852
853impl Default for HashesOrTransactionInfos {
854 fn default() -> Self {
855 HashesOrTransactionInfos::Hashes(Default::default())
856 }
857}
858
859impl From<HashesOrTransactionInfos> for HashesOrTransactionInfosV1 {
860 fn from(value: HashesOrTransactionInfos) -> Self {
861 match value {
862 HashesOrTransactionInfos::Hashes(hashes) => Self::Hashes(hashes),
863 HashesOrTransactionInfos::TransactionInfos(infos) => {
864 Self::TransactionInfos(infos.into_iter().map(Into::into).collect())
865 },
866 }
867 }
868}
869
870impl HashesOrTransactionInfos {
871 pub fn push_hash(&mut self, hash: H256) {
872 match self {
873 HashesOrTransactionInfos::Hashes(hashes) => hashes.push(hash),
874 _ => {},
875 }
876 }
877
878 pub fn len(&self) -> usize {
879 match self {
880 HashesOrTransactionInfos::Hashes(v) => v.len(),
881 HashesOrTransactionInfos::TransactionInfos(v) => v.len(),
882 }
883 }
884
885 pub fn is_empty(&self) -> bool {
886 self.len() == 0
887 }
888
889 pub fn contains_tx(&self, hash: H256) -> bool {
890 match self {
891 HashesOrTransactionInfos::Hashes(hashes) => hashes.iter().any(|h256| *h256 == hash),
892 HashesOrTransactionInfos::TransactionInfos(transaction_infos) => {
893 transaction_infos.iter().any(|ti| ti.hash == hash)
894 },
895 }
896 }
897}
898
899#[derive(Debug, Default, Clone, Eq, PartialEq)]
901pub struct InputOrData {
902 input: Option<Bytes>,
903 data: Option<Bytes>,
904}
905
906impl From<Bytes> for InputOrData {
907 fn from(value: Bytes) -> Self {
908 InputOrData { input: Some(value), data: None }
909 }
910}
911
912impl From<Vec<u8>> for InputOrData {
913 fn from(value: Vec<u8>) -> Self {
914 InputOrData { input: Some(Bytes(value)), data: None }
915 }
916}
917
918impl InputOrData {
919 pub fn to_bytes(self) -> Bytes {
921 match self {
922 InputOrData { input: Some(input), data: _ } => input,
923 InputOrData { input: None, data: Some(data) } => data,
924 _ => Default::default(),
925 }
926 }
927
928 pub fn to_vec(self) -> Vec<u8> {
930 self.to_bytes().0
931 }
932
933 pub fn as_slice(&self) -> &[u8] {
935 self.input
936 .as_ref()
937 .or(self.data.as_ref())
938 .map(|bytes| bytes.0.as_slice())
939 .unwrap_or_default()
940 }
941
942 pub fn is_empty(&self) -> bool {
944 self.as_slice().is_empty()
945 }
946}
947
948impl From<InputOrDataV1> for InputOrData {
949 fn from(value: InputOrDataV1) -> Self {
950 Self { input: value.input, data: value.data }
951 }
952}
953
954impl From<InputOrData> for InputOrDataV1 {
955 fn from(value: InputOrData) -> Self {
956 Self { input: value.input, data: value.data }
957 }
958}
959
960#[cfg(test)]
961mod tests {
962 use crate::evm::*;
963
964 #[test]
965 fn from_unsigned_works_for_legacy() {
966 let base_gas_price = U256::from(10);
967 let tx = TransactionUnsigned::from(TransactionLegacyUnsigned {
968 chain_id: Some(U256::from(1)),
969 input: Bytes::from(vec![1u8]),
970 nonce: U256::from(1),
971 value: U256::from(1),
972 to: Some(H160::zero()),
973 gas: U256::from(1),
974 gas_price: U256::from(10),
975 ..Default::default()
976 });
977
978 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
979 assert_eq!(generic.gas_price, Some(U256::from(10)));
980
981 let tx2 = generic.try_into_unsigned().unwrap();
982 assert_eq!(tx, tx2);
983 }
984
985 #[test]
986 fn from_unsigned_works_for_1559() {
987 let base_gas_price = U256::from(10);
988 let tx = TransactionUnsigned::from(Transaction1559Unsigned {
989 chain_id: U256::from(1),
990 input: Bytes::from(vec![1u8]),
991 nonce: U256::from(1),
992 value: U256::from(1),
993 to: Some(H160::zero()),
994 gas: U256::from(1),
995 gas_price: U256::from(20),
996 max_fee_per_gas: U256::from(20),
997 max_priority_fee_per_gas: U256::from(1),
998 ..Default::default()
999 });
1000
1001 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
1002 assert_eq!(generic.gas_price, Some(U256::from(10)));
1003
1004 let tx2 = generic.try_into_unsigned().unwrap();
1005 assert_eq!(tx, tx2);
1006 }
1007
1008 #[test]
1009 fn from_unsigned_works_for_7702() {
1010 let base_gas_price = U256::from(10);
1011 let tx = TransactionUnsigned::from(Transaction7702Unsigned {
1012 chain_id: U256::from(1),
1013 input: Bytes::from(vec![1u8]),
1014 nonce: U256::from(1),
1015 value: U256::from(1),
1016 to: H160::zero(),
1017 gas: U256::from(1),
1018 max_fee_per_gas: U256::from(20),
1019 max_priority_fee_per_gas: U256::from(1),
1020 authorization_list: vec![AuthorizationListEntry {
1021 chain_id: U256::from(1),
1022 address: H160::from_low_u64_be(42),
1023 nonce: U256::from(0),
1024 y_parity: U256::from(1),
1025 r: U256::from(1),
1026 s: U256::from(2),
1027 }],
1028 ..Default::default()
1029 });
1030
1031 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
1032 assert_eq!(generic.gas_price, Some(U256::from(10)));
1033
1034 let tx2 = generic.try_into_unsigned().unwrap();
1035 assert_eq!(tx, tx2);
1036 }
1037}