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
388pub fn synthetic_log_transaction(block_number: U256, chain_id: U256) -> Vec<u8> {
398 TransactionUnsigned::from(TransactionLegacyUnsigned {
399 nonce: block_number,
400 chain_id: Some(chain_id),
401 ..Default::default()
402 })
403 .dummy_signed_payload()
404}
405
406impl From<TransactionSigned> for TransactionUnsigned {
407 fn from(tx: TransactionSigned) -> Self {
408 use TransactionSigned::*;
409 match tx {
410 Transaction7702Signed(tx) => tx.transaction_7702_unsigned.into(),
411 Transaction4844Signed(tx) => tx.transaction_4844_unsigned.into(),
412 Transaction1559Signed(tx) => tx.transaction_1559_unsigned.into(),
413 Transaction2930Signed(tx) => tx.transaction_2930_unsigned.into(),
414 TransactionLegacySigned(tx) => tx.transaction_legacy_unsigned.into(),
415 }
416 }
417}
418
419#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
421pub struct Transaction1559Unsigned {
422 pub access_list: AccessList,
425 pub chain_id: U256,
428 pub gas: U256,
430 pub gas_price: U256,
435 pub input: Bytes,
437 pub max_fee_per_gas: U256,
441 pub max_priority_fee_per_gas: U256,
444 pub nonce: U256,
446 pub to: Option<Address>,
448 pub r#type: TypeEip1559,
450 pub value: U256,
452}
453
454impl From<Transaction1559Unsigned> for Transaction1559UnsignedV1 {
455 fn from(value: Transaction1559Unsigned) -> Self {
456 Self {
457 access_list: value.access_list.into_iter().map(Into::into).collect(),
458 chain_id: value.chain_id,
459 gas: value.gas,
460 gas_price: value.gas_price,
461 input: value.input,
462 max_fee_per_gas: value.max_fee_per_gas,
463 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
464 nonce: value.nonce,
465 to: value.to,
466 r#type: value.r#type,
467 value: value.value,
468 }
469 }
470}
471
472#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
474pub struct Transaction2930Unsigned {
475 pub access_list: AccessList,
478 pub chain_id: U256,
481 pub gas: U256,
483 pub gas_price: U256,
486 pub input: Bytes,
488 pub nonce: U256,
490 pub to: Option<Address>,
492 pub r#type: TypeEip2930,
494 pub value: U256,
496}
497
498impl From<Transaction2930Unsigned> for Transaction2930UnsignedV1 {
499 fn from(value: Transaction2930Unsigned) -> Self {
500 Self {
501 access_list: value.access_list.into_iter().map(Into::into).collect(),
502 chain_id: value.chain_id,
503 gas: value.gas,
504 gas_price: value.gas_price,
505 input: value.input,
506 nonce: value.nonce,
507 to: value.to,
508 r#type: value.r#type,
509 value: value.value,
510 }
511 }
512}
513
514#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
516pub struct Transaction4844Unsigned {
517 pub access_list: AccessList,
520 pub blob_versioned_hashes: Vec<H256>,
523 pub chain_id: U256,
526 pub gas: U256,
528 pub input: Bytes,
530 pub max_fee_per_blob_gas: U256,
533 pub max_fee_per_gas: U256,
537 pub max_priority_fee_per_gas: U256,
540 pub nonce: U256,
542 pub to: Address,
544 pub r#type: TypeEip4844,
546 pub value: U256,
548}
549
550impl From<Transaction4844Unsigned> for Transaction4844UnsignedV1 {
551 fn from(value: Transaction4844Unsigned) -> Self {
552 Self {
553 access_list: value.access_list.into_iter().map(Into::into).collect(),
554 blob_versioned_hashes: value.blob_versioned_hashes,
555 chain_id: value.chain_id,
556 gas: value.gas,
557 input: value.input,
558 max_fee_per_blob_gas: value.max_fee_per_blob_gas,
559 max_fee_per_gas: value.max_fee_per_gas,
560 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
561 nonce: value.nonce,
562 to: value.to,
563 r#type: value.r#type,
564 value: value.value,
565 }
566 }
567}
568
569#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
571pub struct TransactionLegacyUnsigned {
572 pub chain_id: Option<U256>,
575 pub gas: U256,
577 pub gas_price: U256,
580 pub input: Bytes,
582 pub nonce: U256,
584 pub to: Option<Address>,
586 pub r#type: TypeLegacy,
588 pub value: U256,
590}
591
592impl From<TransactionLegacyUnsigned> for TransactionLegacyUnsignedV1 {
593 fn from(value: TransactionLegacyUnsigned) -> Self {
594 Self {
595 chain_id: value.chain_id,
596 gas: value.gas,
597 gas_price: value.gas_price,
598 input: value.input,
599 nonce: value.nonce,
600 to: value.to,
601 r#type: value.r#type,
602 value: value.value,
603 }
604 }
605}
606
607#[derive(
609 Debug, Clone, Default, From, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking,
610)]
611pub struct Transaction7702Unsigned {
612 pub access_list: AccessList,
615 pub authorization_list: Vec<AuthorizationListEntry>,
618 pub chain_id: U256,
621 pub gas: U256,
623 pub input: Bytes,
625 pub max_fee_per_gas: U256,
629 pub max_priority_fee_per_gas: U256,
632 pub nonce: U256,
634 pub to: Address,
640 pub r#type: TypeEip7702,
642 pub value: U256,
644}
645
646impl From<Transaction7702Unsigned> for Transaction7702UnsignedV1 {
647 fn from(value: Transaction7702Unsigned) -> Self {
648 Self {
649 access_list: value.access_list.into_iter().map(Into::into).collect(),
650 authorization_list: value.authorization_list.into_iter().map(Into::into).collect(),
651 chain_id: value.chain_id,
652 gas: value.gas,
653 input: value.input,
654 max_fee_per_gas: value.max_fee_per_gas,
655 max_priority_fee_per_gas: value.max_priority_fee_per_gas,
656 nonce: value.nonce,
657 to: value.to,
658 r#type: value.r#type,
659 value: value.value,
660 }
661 }
662}
663
664#[derive(Debug, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
666pub struct Transaction7702Signed {
667 pub transaction_7702_unsigned: Transaction7702Unsigned,
668 pub r: U256,
670 pub s: U256,
672 pub v: Option<U256>,
676 pub y_parity: U256,
679}
680
681impl From<Transaction7702Signed> for Transaction7702SignedV1 {
682 fn from(value: Transaction7702Signed) -> Self {
683 Self {
684 transaction_7702_unsigned: value.transaction_7702_unsigned.into(),
685 r: value.r,
686 s: value.s,
687 v: value.v,
688 y_parity: value.y_parity,
689 }
690 }
691}
692
693#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
695pub struct Transaction1559Signed {
696 pub transaction_1559_unsigned: Transaction1559Unsigned,
697 pub r: U256,
699 pub s: U256,
701 pub v: Option<U256>,
705 pub y_parity: U256,
708}
709
710impl From<Transaction1559Signed> for Transaction1559SignedV1 {
711 fn from(value: Transaction1559Signed) -> Self {
712 Self {
713 transaction_1559_unsigned: value.transaction_1559_unsigned.into(),
714 r: value.r,
715 s: value.s,
716 v: value.v,
717 y_parity: value.y_parity,
718 }
719 }
720}
721
722#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
724pub struct Transaction2930Signed {
725 pub transaction_2930_unsigned: Transaction2930Unsigned,
726 pub r: U256,
728 pub s: U256,
730 pub v: Option<U256>,
734 pub y_parity: U256,
737}
738
739impl From<Transaction2930Signed> for Transaction2930SignedV1 {
740 fn from(value: Transaction2930Signed) -> Self {
741 Self {
742 transaction_2930_unsigned: value.transaction_2930_unsigned.into(),
743 r: value.r,
744 s: value.s,
745 v: value.v,
746 y_parity: value.y_parity,
747 }
748 }
749}
750
751#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
753pub struct Transaction4844Signed {
754 pub transaction_4844_unsigned: Transaction4844Unsigned,
755 pub r: U256,
757 pub s: U256,
759 pub y_parity: U256,
762}
763
764impl From<Transaction4844Signed> for Transaction4844SignedV1 {
765 fn from(value: Transaction4844Signed) -> Self {
766 Self {
767 transaction_4844_unsigned: value.transaction_4844_unsigned.into(),
768 r: value.r,
769 s: value.s,
770 y_parity: value.y_parity,
771 }
772 }
773}
774
775#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
777pub struct TransactionLegacySigned {
778 pub transaction_legacy_unsigned: TransactionLegacyUnsigned,
779 pub r: U256,
781 pub s: U256,
783 pub v: U256,
785}
786
787impl From<TransactionLegacySigned> for TransactionLegacySignedV1 {
788 fn from(value: TransactionLegacySigned) -> Self {
789 Self {
790 transaction_legacy_unsigned: value.transaction_legacy_unsigned.into(),
791 r: value.r,
792 s: value.s,
793 v: value.v,
794 }
795 }
796}
797
798pub type AccessList = Vec<AccessListEntry>;
800
801#[derive(Debug, Default, Clone, Encode, Decode, TypeInfo, Eq, PartialEq, DecodeWithMemTracking)]
803pub struct AccessListEntry {
804 pub address: Address,
805 pub storage_keys: Vec<H256>,
806}
807
808impl From<AccessListEntryV1> for AccessListEntry {
809 fn from(value: AccessListEntryV1) -> Self {
810 Self { address: value.address, storage_keys: value.storage_keys }
811 }
812}
813
814impl From<AccessListEntry> for AccessListEntryV1 {
815 fn from(value: AccessListEntry) -> Self {
816 Self { address: value.address, storage_keys: value.storage_keys }
817 }
818}
819
820#[derive(Debug, Default, Clone, Eq, PartialEq, TypeInfo, Encode, Decode, DecodeWithMemTracking)]
822pub struct AuthorizationListEntry {
823 pub chain_id: U256,
825 pub address: Address,
827 pub nonce: U256,
829 pub y_parity: U256,
831 pub r: U256,
833 pub s: U256,
835}
836
837impl AuthorizationListEntry {
838 pub fn signature(&self) -> [u8; 65] {
840 let mut signature = [0u8; 65];
841 signature[..32].copy_from_slice(&self.r.to_big_endian());
842 signature[32..64].copy_from_slice(&self.s.to_big_endian());
843 signature[64] = self.y_parity.low_u32() as u8;
844 signature
845 }
846}
847
848impl From<AuthorizationListEntryV1> for AuthorizationListEntry {
849 fn from(value: AuthorizationListEntryV1) -> Self {
850 Self {
851 chain_id: value.chain_id,
852 address: value.address,
853 nonce: value.nonce,
854 y_parity: value.y_parity,
855 r: value.r,
856 s: value.s,
857 }
858 }
859}
860
861impl From<AuthorizationListEntry> for AuthorizationListEntryV1 {
862 fn from(value: AuthorizationListEntry) -> Self {
863 Self {
864 chain_id: value.chain_id,
865 address: value.address,
866 nonce: value.nonce,
867 y_parity: value.y_parity,
868 r: value.r,
869 s: value.s,
870 }
871 }
872}
873
874#[derive(Debug, Clone, From, TryInto, Eq, PartialEq, TypeInfo, Encode, Decode)]
875pub enum HashesOrTransactionInfos {
876 Hashes(Vec<H256>),
878 TransactionInfos(Vec<TransactionInfo>),
880}
881
882impl Default for HashesOrTransactionInfos {
883 fn default() -> Self {
884 HashesOrTransactionInfos::Hashes(Default::default())
885 }
886}
887
888impl From<HashesOrTransactionInfos> for HashesOrTransactionInfosV1 {
889 fn from(value: HashesOrTransactionInfos) -> Self {
890 match value {
891 HashesOrTransactionInfos::Hashes(hashes) => Self::Hashes(hashes),
892 HashesOrTransactionInfos::TransactionInfos(infos) => {
893 Self::TransactionInfos(infos.into_iter().map(Into::into).collect())
894 },
895 }
896 }
897}
898
899impl HashesOrTransactionInfos {
900 pub fn push_hash(&mut self, hash: H256) {
901 match self {
902 HashesOrTransactionInfos::Hashes(hashes) => hashes.push(hash),
903 _ => {},
904 }
905 }
906
907 pub fn len(&self) -> usize {
908 match self {
909 HashesOrTransactionInfos::Hashes(v) => v.len(),
910 HashesOrTransactionInfos::TransactionInfos(v) => v.len(),
911 }
912 }
913
914 pub fn is_empty(&self) -> bool {
915 self.len() == 0
916 }
917
918 pub fn contains_tx(&self, hash: H256) -> bool {
919 match self {
920 HashesOrTransactionInfos::Hashes(hashes) => hashes.iter().any(|h256| *h256 == hash),
921 HashesOrTransactionInfos::TransactionInfos(transaction_infos) => {
922 transaction_infos.iter().any(|ti| ti.hash == hash)
923 },
924 }
925 }
926}
927
928#[derive(Debug, Default, Clone, Eq, PartialEq)]
930pub struct InputOrData {
931 input: Option<Bytes>,
932 data: Option<Bytes>,
933}
934
935impl From<Bytes> for InputOrData {
936 fn from(value: Bytes) -> Self {
937 InputOrData { input: Some(value), data: None }
938 }
939}
940
941impl From<Vec<u8>> for InputOrData {
942 fn from(value: Vec<u8>) -> Self {
943 InputOrData { input: Some(Bytes(value)), data: None }
944 }
945}
946
947impl InputOrData {
948 pub fn to_bytes(self) -> Bytes {
950 match self {
951 InputOrData { input: Some(input), data: _ } => input,
952 InputOrData { input: None, data: Some(data) } => data,
953 _ => Default::default(),
954 }
955 }
956
957 pub fn to_vec(self) -> Vec<u8> {
959 self.to_bytes().0
960 }
961
962 pub fn as_slice(&self) -> &[u8] {
964 self.input
965 .as_ref()
966 .or(self.data.as_ref())
967 .map(|bytes| bytes.0.as_slice())
968 .unwrap_or_default()
969 }
970
971 pub fn is_empty(&self) -> bool {
973 self.as_slice().is_empty()
974 }
975}
976
977impl From<InputOrDataV1> for InputOrData {
978 fn from(value: InputOrDataV1) -> Self {
979 Self { input: value.input, data: value.data }
980 }
981}
982
983impl From<InputOrData> for InputOrDataV1 {
984 fn from(value: InputOrData) -> Self {
985 Self { input: value.input, data: value.data }
986 }
987}
988
989#[cfg(test)]
990mod tests {
991 use crate::evm::*;
992
993 #[test]
994 fn from_unsigned_works_for_legacy() {
995 let base_gas_price = U256::from(10);
996 let tx = TransactionUnsigned::from(TransactionLegacyUnsigned {
997 chain_id: Some(U256::from(1)),
998 input: Bytes::from(vec![1u8]),
999 nonce: U256::from(1),
1000 value: U256::from(1),
1001 to: Some(H160::zero()),
1002 gas: U256::from(1),
1003 gas_price: U256::from(10),
1004 ..Default::default()
1005 });
1006
1007 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
1008 assert_eq!(generic.gas_price, Some(U256::from(10)));
1009
1010 let tx2 = generic.try_into_unsigned().unwrap();
1011 assert_eq!(tx, tx2);
1012 }
1013
1014 #[test]
1015 fn from_unsigned_works_for_1559() {
1016 let base_gas_price = U256::from(10);
1017 let tx = TransactionUnsigned::from(Transaction1559Unsigned {
1018 chain_id: U256::from(1),
1019 input: Bytes::from(vec![1u8]),
1020 nonce: U256::from(1),
1021 value: U256::from(1),
1022 to: Some(H160::zero()),
1023 gas: U256::from(1),
1024 gas_price: U256::from(20),
1025 max_fee_per_gas: U256::from(20),
1026 max_priority_fee_per_gas: U256::from(1),
1027 ..Default::default()
1028 });
1029
1030 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
1031 assert_eq!(generic.gas_price, Some(U256::from(10)));
1032
1033 let tx2 = generic.try_into_unsigned().unwrap();
1034 assert_eq!(tx, tx2);
1035 }
1036
1037 #[test]
1038 fn from_unsigned_works_for_7702() {
1039 let base_gas_price = U256::from(10);
1040 let tx = TransactionUnsigned::from(Transaction7702Unsigned {
1041 chain_id: U256::from(1),
1042 input: Bytes::from(vec![1u8]),
1043 nonce: U256::from(1),
1044 value: U256::from(1),
1045 to: H160::zero(),
1046 gas: U256::from(1),
1047 max_fee_per_gas: U256::from(20),
1048 max_priority_fee_per_gas: U256::from(1),
1049 authorization_list: vec![AuthorizationListEntry {
1050 chain_id: U256::from(1),
1051 address: H160::from_low_u64_be(42),
1052 nonce: U256::from(0),
1053 y_parity: U256::from(1),
1054 r: U256::from(1),
1055 s: U256::from(2),
1056 }],
1057 ..Default::default()
1058 });
1059
1060 let generic = GenericTransaction::from_unsigned(tx.clone(), base_gas_price, None);
1061 assert_eq!(generic.gas_price, Some(U256::from(10)));
1062
1063 let tx2 = generic.try_into_unsigned().unwrap();
1064 assert_eq!(tx, tx2);
1065 }
1066}