1use crate::{
2 transaction::{
3 eip4844::{TxEip4844, TxEip4844Variant, TxEip4844WithSidecar},
4 RlpEcdsaEncodableTx,
5 },
6 EthereumTxEnvelope, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702,
7 TxLegacy, TxType,
8};
9use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization, Typed2718};
10use alloy_primitives::{bytes::BufMut, Bytes, ChainId, Signature, TxHash, TxKind, B256, U256};
11
12pub type TypedTransaction = EthereumTypedTransaction<TxEip4844Variant>;
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32#[cfg_attr(
33 feature = "serde",
34 serde(
35 from = "serde_from::MaybeTaggedTypedTransaction<Eip4844>",
36 into = "serde_from::TaggedTypedTransaction<Eip4844>",
37 bound = "Eip4844: Clone + serde::Serialize + serde::de::DeserializeOwned"
38 )
39)]
40#[cfg_attr(all(any(test, feature = "arbitrary"), feature = "k256"), derive(arbitrary::Arbitrary))]
41#[doc(alias = "TypedTx", alias = "TxTyped", alias = "TransactionTyped")]
42pub enum EthereumTypedTransaction<Eip4844> {
43 #[cfg_attr(feature = "serde", serde(rename = "0x00", alias = "0x0"))]
45 Legacy(TxLegacy),
46 #[cfg_attr(feature = "serde", serde(rename = "0x01", alias = "0x1"))]
48 Eip2930(TxEip2930),
49 #[cfg_attr(feature = "serde", serde(rename = "0x02", alias = "0x2"))]
51 Eip1559(TxEip1559),
52 #[cfg_attr(feature = "serde", serde(rename = "0x03", alias = "0x3"))]
54 Eip4844(Eip4844),
55 #[cfg_attr(feature = "serde", serde(rename = "0x04", alias = "0x4"))]
57 Eip7702(TxEip7702),
58}
59
60impl<Eip4844> From<TxLegacy> for EthereumTypedTransaction<Eip4844> {
61 fn from(tx: TxLegacy) -> Self {
62 Self::Legacy(tx)
63 }
64}
65
66impl<Eip4844> From<TxEip2930> for EthereumTypedTransaction<Eip4844> {
67 fn from(tx: TxEip2930) -> Self {
68 Self::Eip2930(tx)
69 }
70}
71
72impl<Eip4844> From<TxEip1559> for EthereumTypedTransaction<Eip4844> {
73 fn from(tx: TxEip1559) -> Self {
74 Self::Eip1559(tx)
75 }
76}
77
78impl<Eip4844: From<TxEip4844>> From<TxEip4844> for EthereumTypedTransaction<Eip4844> {
79 fn from(tx: TxEip4844) -> Self {
80 Self::Eip4844(tx.into())
81 }
82}
83
84impl<Eip4844: From<TxEip4844WithSidecar>> From<TxEip4844WithSidecar>
85 for EthereumTypedTransaction<Eip4844>
86{
87 fn from(tx: TxEip4844WithSidecar) -> Self {
88 Self::Eip4844(tx.into())
89 }
90}
91
92impl<Eip4844: From<TxEip4844Variant>> From<TxEip4844Variant> for EthereumTypedTransaction<Eip4844> {
93 fn from(tx: TxEip4844Variant) -> Self {
94 Self::Eip4844(tx.into())
95 }
96}
97
98impl<Eip4844> From<TxEip7702> for EthereumTypedTransaction<Eip4844> {
99 fn from(tx: TxEip7702) -> Self {
100 Self::Eip7702(tx)
101 }
102}
103
104impl<Eip4844> From<EthereumTxEnvelope<Eip4844>> for EthereumTypedTransaction<Eip4844> {
105 fn from(envelope: EthereumTxEnvelope<Eip4844>) -> Self {
106 match envelope {
107 EthereumTxEnvelope::Legacy(tx) => Self::Legacy(tx.strip_signature()),
108 EthereumTxEnvelope::Eip2930(tx) => Self::Eip2930(tx.strip_signature()),
109 EthereumTxEnvelope::Eip1559(tx) => Self::Eip1559(tx.strip_signature()),
110 EthereumTxEnvelope::Eip4844(tx) => Self::Eip4844(tx.strip_signature()),
111 EthereumTxEnvelope::Eip7702(tx) => Self::Eip7702(tx.strip_signature()),
112 }
113 }
114}
115
116impl<Eip4844: RlpEcdsaEncodableTx> EthereumTypedTransaction<Eip4844> {
117 #[doc(alias = "transaction_type")]
119 pub const fn tx_type(&self) -> TxType {
120 match self {
121 Self::Legacy(_) => TxType::Legacy,
122 Self::Eip2930(_) => TxType::Eip2930,
123 Self::Eip1559(_) => TxType::Eip1559,
124 Self::Eip4844(_) => TxType::Eip4844,
125 Self::Eip7702(_) => TxType::Eip7702,
126 }
127 }
128
129 pub const fn legacy(&self) -> Option<&TxLegacy> {
131 match self {
132 Self::Legacy(tx) => Some(tx),
133 _ => None,
134 }
135 }
136
137 pub const fn eip2930(&self) -> Option<&TxEip2930> {
139 match self {
140 Self::Eip2930(tx) => Some(tx),
141 _ => None,
142 }
143 }
144
145 pub const fn eip1559(&self) -> Option<&TxEip1559> {
147 match self {
148 Self::Eip1559(tx) => Some(tx),
149 _ => None,
150 }
151 }
152
153 pub const fn eip7702(&self) -> Option<&TxEip7702> {
155 match self {
156 Self::Eip7702(tx) => Some(tx),
157 _ => None,
158 }
159 }
160
161 pub fn tx_hash(&self, signature: &Signature) -> TxHash {
163 match self {
164 Self::Legacy(tx) => tx.tx_hash(signature),
165 Self::Eip2930(tx) => tx.tx_hash(signature),
166 Self::Eip1559(tx) => tx.tx_hash(signature),
167 Self::Eip4844(tx) => tx.tx_hash(signature),
168 Self::Eip7702(tx) => tx.tx_hash(signature),
169 }
170 }
171}
172
173impl<Eip4844: Transaction> Transaction for EthereumTypedTransaction<Eip4844> {
174 #[inline]
175 fn chain_id(&self) -> Option<ChainId> {
176 match self {
177 Self::Legacy(tx) => tx.chain_id(),
178 Self::Eip2930(tx) => tx.chain_id(),
179 Self::Eip1559(tx) => tx.chain_id(),
180 Self::Eip4844(tx) => tx.chain_id(),
181 Self::Eip7702(tx) => tx.chain_id(),
182 }
183 }
184
185 #[inline]
186 fn nonce(&self) -> u64 {
187 match self {
188 Self::Legacy(tx) => tx.nonce(),
189 Self::Eip2930(tx) => tx.nonce(),
190 Self::Eip1559(tx) => tx.nonce(),
191 Self::Eip4844(tx) => tx.nonce(),
192 Self::Eip7702(tx) => tx.nonce(),
193 }
194 }
195
196 #[inline]
197 fn gas_limit(&self) -> u64 {
198 match self {
199 Self::Legacy(tx) => tx.gas_limit(),
200 Self::Eip2930(tx) => tx.gas_limit(),
201 Self::Eip1559(tx) => tx.gas_limit(),
202 Self::Eip4844(tx) => tx.gas_limit(),
203 Self::Eip7702(tx) => tx.gas_limit(),
204 }
205 }
206
207 #[inline]
208 fn gas_price(&self) -> Option<u128> {
209 match self {
210 Self::Legacy(tx) => tx.gas_price(),
211 Self::Eip2930(tx) => tx.gas_price(),
212 Self::Eip1559(tx) => tx.gas_price(),
213 Self::Eip4844(tx) => tx.gas_price(),
214 Self::Eip7702(tx) => tx.gas_price(),
215 }
216 }
217
218 #[inline]
219 fn max_fee_per_gas(&self) -> u128 {
220 match self {
221 Self::Legacy(tx) => tx.max_fee_per_gas(),
222 Self::Eip2930(tx) => tx.max_fee_per_gas(),
223 Self::Eip1559(tx) => tx.max_fee_per_gas(),
224 Self::Eip4844(tx) => tx.max_fee_per_gas(),
225 Self::Eip7702(tx) => tx.max_fee_per_gas(),
226 }
227 }
228
229 #[inline]
230 fn max_priority_fee_per_gas(&self) -> Option<u128> {
231 match self {
232 Self::Legacy(tx) => tx.max_priority_fee_per_gas(),
233 Self::Eip2930(tx) => tx.max_priority_fee_per_gas(),
234 Self::Eip1559(tx) => tx.max_priority_fee_per_gas(),
235 Self::Eip4844(tx) => tx.max_priority_fee_per_gas(),
236 Self::Eip7702(tx) => tx.max_priority_fee_per_gas(),
237 }
238 }
239
240 #[inline]
241 fn max_fee_per_blob_gas(&self) -> Option<u128> {
242 match self {
243 Self::Legacy(tx) => tx.max_fee_per_blob_gas(),
244 Self::Eip2930(tx) => tx.max_fee_per_blob_gas(),
245 Self::Eip1559(tx) => tx.max_fee_per_blob_gas(),
246 Self::Eip4844(tx) => tx.max_fee_per_blob_gas(),
247 Self::Eip7702(tx) => tx.max_fee_per_blob_gas(),
248 }
249 }
250
251 #[inline]
252 fn priority_fee_or_price(&self) -> u128 {
253 match self {
254 Self::Legacy(tx) => tx.priority_fee_or_price(),
255 Self::Eip2930(tx) => tx.priority_fee_or_price(),
256 Self::Eip1559(tx) => tx.priority_fee_or_price(),
257 Self::Eip4844(tx) => tx.priority_fee_or_price(),
258 Self::Eip7702(tx) => tx.priority_fee_or_price(),
259 }
260 }
261
262 fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
263 match self {
264 Self::Legacy(tx) => tx.effective_gas_price(base_fee),
265 Self::Eip2930(tx) => tx.effective_gas_price(base_fee),
266 Self::Eip1559(tx) => tx.effective_gas_price(base_fee),
267 Self::Eip4844(tx) => tx.effective_gas_price(base_fee),
268 Self::Eip7702(tx) => tx.effective_gas_price(base_fee),
269 }
270 }
271
272 #[inline]
273 fn is_dynamic_fee(&self) -> bool {
274 match self {
275 Self::Legacy(tx) => tx.is_dynamic_fee(),
276 Self::Eip2930(tx) => tx.is_dynamic_fee(),
277 Self::Eip1559(tx) => tx.is_dynamic_fee(),
278 Self::Eip4844(tx) => tx.is_dynamic_fee(),
279 Self::Eip7702(tx) => tx.is_dynamic_fee(),
280 }
281 }
282
283 #[inline]
284 fn kind(&self) -> TxKind {
285 match self {
286 Self::Legacy(tx) => tx.kind(),
287 Self::Eip2930(tx) => tx.kind(),
288 Self::Eip1559(tx) => tx.kind(),
289 Self::Eip4844(tx) => tx.kind(),
290 Self::Eip7702(tx) => tx.kind(),
291 }
292 }
293
294 #[inline]
295 fn is_create(&self) -> bool {
296 match self {
297 Self::Legacy(tx) => tx.is_create(),
298 Self::Eip2930(tx) => tx.is_create(),
299 Self::Eip1559(tx) => tx.is_create(),
300 Self::Eip4844(tx) => tx.is_create(),
301 Self::Eip7702(tx) => tx.is_create(),
302 }
303 }
304
305 #[inline]
306 fn value(&self) -> U256 {
307 match self {
308 Self::Legacy(tx) => tx.value(),
309 Self::Eip2930(tx) => tx.value(),
310 Self::Eip1559(tx) => tx.value(),
311 Self::Eip4844(tx) => tx.value(),
312 Self::Eip7702(tx) => tx.value(),
313 }
314 }
315
316 #[inline]
317 fn input(&self) -> &Bytes {
318 match self {
319 Self::Legacy(tx) => tx.input(),
320 Self::Eip2930(tx) => tx.input(),
321 Self::Eip1559(tx) => tx.input(),
322 Self::Eip4844(tx) => tx.input(),
323 Self::Eip7702(tx) => tx.input(),
324 }
325 }
326
327 #[inline]
328 fn access_list(&self) -> Option<&AccessList> {
329 match self {
330 Self::Legacy(tx) => tx.access_list(),
331 Self::Eip2930(tx) => tx.access_list(),
332 Self::Eip1559(tx) => tx.access_list(),
333 Self::Eip4844(tx) => tx.access_list(),
334 Self::Eip7702(tx) => tx.access_list(),
335 }
336 }
337
338 #[inline]
339 fn blob_versioned_hashes(&self) -> Option<&[B256]> {
340 match self {
341 Self::Legacy(tx) => tx.blob_versioned_hashes(),
342 Self::Eip2930(tx) => tx.blob_versioned_hashes(),
343 Self::Eip1559(tx) => tx.blob_versioned_hashes(),
344 Self::Eip4844(tx) => tx.blob_versioned_hashes(),
345 Self::Eip7702(tx) => tx.blob_versioned_hashes(),
346 }
347 }
348
349 #[inline]
350 fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
351 match self {
352 Self::Legacy(tx) => tx.authorization_list(),
353 Self::Eip2930(tx) => tx.authorization_list(),
354 Self::Eip1559(tx) => tx.authorization_list(),
355 Self::Eip4844(tx) => tx.authorization_list(),
356 Self::Eip7702(tx) => tx.authorization_list(),
357 }
358 }
359}
360
361impl<Eip4844: Typed2718> Typed2718 for EthereumTypedTransaction<Eip4844> {
362 fn ty(&self) -> u8 {
363 match self {
364 Self::Legacy(tx) => tx.ty(),
365 Self::Eip2930(tx) => tx.ty(),
366 Self::Eip1559(tx) => tx.ty(),
367 Self::Eip4844(tx) => tx.ty(),
368 Self::Eip7702(tx) => tx.ty(),
369 }
370 }
371}
372
373impl<Eip4844: RlpEcdsaEncodableTx + Typed2718> RlpEcdsaEncodableTx
374 for EthereumTypedTransaction<Eip4844>
375{
376 fn rlp_encoded_fields_length(&self) -> usize {
377 match self {
378 Self::Legacy(tx) => tx.rlp_encoded_fields_length(),
379 Self::Eip2930(tx) => tx.rlp_encoded_fields_length(),
380 Self::Eip1559(tx) => tx.rlp_encoded_fields_length(),
381 Self::Eip4844(tx) => tx.rlp_encoded_fields_length(),
382 Self::Eip7702(tx) => tx.rlp_encoded_fields_length(),
383 }
384 }
385
386 fn rlp_encode_fields(&self, out: &mut dyn alloy_rlp::BufMut) {
387 match self {
388 Self::Legacy(tx) => tx.rlp_encode_fields(out),
389 Self::Eip2930(tx) => tx.rlp_encode_fields(out),
390 Self::Eip1559(tx) => tx.rlp_encode_fields(out),
391 Self::Eip4844(tx) => tx.rlp_encode_fields(out),
392 Self::Eip7702(tx) => tx.rlp_encode_fields(out),
393 }
394 }
395
396 fn eip2718_encode_with_type(&self, signature: &Signature, _ty: u8, out: &mut dyn BufMut) {
397 match self {
398 Self::Legacy(tx) => tx.eip2718_encode_with_type(signature, tx.ty(), out),
399 Self::Eip2930(tx) => tx.eip2718_encode_with_type(signature, tx.ty(), out),
400 Self::Eip1559(tx) => tx.eip2718_encode_with_type(signature, tx.ty(), out),
401 Self::Eip4844(tx) => tx.eip2718_encode_with_type(signature, tx.ty(), out),
402 Self::Eip7702(tx) => tx.eip2718_encode_with_type(signature, tx.ty(), out),
403 }
404 }
405
406 fn eip2718_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
407 match self {
408 Self::Legacy(tx) => tx.eip2718_encode(signature, out),
409 Self::Eip2930(tx) => tx.eip2718_encode(signature, out),
410 Self::Eip1559(tx) => tx.eip2718_encode(signature, out),
411 Self::Eip4844(tx) => tx.eip2718_encode(signature, out),
412 Self::Eip7702(tx) => tx.eip2718_encode(signature, out),
413 }
414 }
415
416 fn network_encode_with_type(&self, signature: &Signature, _ty: u8, out: &mut dyn BufMut) {
417 match self {
418 Self::Legacy(tx) => tx.network_encode_with_type(signature, tx.ty(), out),
419 Self::Eip2930(tx) => tx.network_encode_with_type(signature, tx.ty(), out),
420 Self::Eip1559(tx) => tx.network_encode_with_type(signature, tx.ty(), out),
421 Self::Eip4844(tx) => tx.network_encode_with_type(signature, tx.ty(), out),
422 Self::Eip7702(tx) => tx.network_encode_with_type(signature, tx.ty(), out),
423 }
424 }
425
426 fn network_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
427 match self {
428 Self::Legacy(tx) => tx.network_encode(signature, out),
429 Self::Eip2930(tx) => tx.network_encode(signature, out),
430 Self::Eip1559(tx) => tx.network_encode(signature, out),
431 Self::Eip4844(tx) => tx.network_encode(signature, out),
432 Self::Eip7702(tx) => tx.network_encode(signature, out),
433 }
434 }
435
436 fn tx_hash_with_type(&self, signature: &Signature, _ty: u8) -> TxHash {
437 match self {
438 Self::Legacy(tx) => tx.tx_hash_with_type(signature, tx.ty()),
439 Self::Eip2930(tx) => tx.tx_hash_with_type(signature, tx.ty()),
440 Self::Eip1559(tx) => tx.tx_hash_with_type(signature, tx.ty()),
441 Self::Eip4844(tx) => tx.tx_hash_with_type(signature, tx.ty()),
442 Self::Eip7702(tx) => tx.tx_hash_with_type(signature, tx.ty()),
443 }
444 }
445
446 fn tx_hash(&self, signature: &Signature) -> TxHash {
447 match self {
448 Self::Legacy(tx) => tx.tx_hash(signature),
449 Self::Eip2930(tx) => tx.tx_hash(signature),
450 Self::Eip1559(tx) => tx.tx_hash(signature),
451 Self::Eip4844(tx) => tx.tx_hash(signature),
452 Self::Eip7702(tx) => tx.tx_hash(signature),
453 }
454 }
455}
456
457impl<Eip4844: SignableTransaction<Signature>> SignableTransaction<Signature>
458 for EthereumTypedTransaction<Eip4844>
459{
460 fn set_chain_id(&mut self, chain_id: ChainId) {
461 match self {
462 Self::Legacy(tx) => tx.set_chain_id(chain_id),
463 Self::Eip2930(tx) => tx.set_chain_id(chain_id),
464 Self::Eip1559(tx) => tx.set_chain_id(chain_id),
465 Self::Eip4844(tx) => tx.set_chain_id(chain_id),
466 Self::Eip7702(tx) => tx.set_chain_id(chain_id),
467 }
468 }
469
470 fn encode_for_signing(&self, out: &mut dyn BufMut) {
471 match self {
472 Self::Legacy(tx) => tx.encode_for_signing(out),
473 Self::Eip2930(tx) => tx.encode_for_signing(out),
474 Self::Eip1559(tx) => tx.encode_for_signing(out),
475 Self::Eip4844(tx) => tx.encode_for_signing(out),
476 Self::Eip7702(tx) => tx.encode_for_signing(out),
477 }
478 }
479
480 fn payload_len_for_signature(&self) -> usize {
481 match self {
482 Self::Legacy(tx) => tx.payload_len_for_signature(),
483 Self::Eip2930(tx) => tx.payload_len_for_signature(),
484 Self::Eip1559(tx) => tx.payload_len_for_signature(),
485 Self::Eip4844(tx) => tx.payload_len_for_signature(),
486 Self::Eip7702(tx) => tx.payload_len_for_signature(),
487 }
488 }
489}
490
491#[cfg(feature = "serde")]
492impl<Eip4844, T: From<EthereumTypedTransaction<Eip4844>>> From<EthereumTypedTransaction<Eip4844>>
493 for alloy_serde::WithOtherFields<T>
494{
495 fn from(value: EthereumTypedTransaction<Eip4844>) -> Self {
496 Self::new(value.into())
497 }
498}
499
500#[cfg(feature = "serde")]
501impl<Eip4844, T> From<EthereumTxEnvelope<Eip4844>> for alloy_serde::WithOtherFields<T>
502where
503 T: From<EthereumTxEnvelope<Eip4844>>,
504{
505 fn from(value: EthereumTxEnvelope<Eip4844>) -> Self {
506 Self::new(value.into())
507 }
508}
509
510#[cfg(feature = "serde")]
511mod serde_from {
512 use crate::{EthereumTypedTransaction, TxEip1559, TxEip2930, TxEip7702, TxLegacy};
524
525 #[derive(Debug, serde::Deserialize)]
526 #[serde(untagged)]
527 pub(crate) enum MaybeTaggedTypedTransaction<Eip4844> {
528 Tagged(TaggedTypedTransaction<Eip4844>),
529 Untagged {
530 #[serde(default, rename = "type", deserialize_with = "alloy_serde::reject_if_some")]
531 _ty: Option<()>,
532 #[serde(flatten)]
533 tx: TxLegacy,
534 },
535 }
536
537 #[derive(Debug, serde::Serialize, serde::Deserialize)]
538 #[serde(tag = "type")]
539 pub(crate) enum TaggedTypedTransaction<Eip4844> {
540 #[serde(rename = "0x00", alias = "0x0")]
542 Legacy(TxLegacy),
543 #[serde(rename = "0x01", alias = "0x1")]
545 Eip2930(TxEip2930),
546 #[serde(rename = "0x02", alias = "0x2")]
548 Eip1559(TxEip1559),
549 #[serde(rename = "0x03", alias = "0x3")]
551 Eip4844(Eip4844),
552 #[serde(rename = "0x04", alias = "0x4")]
554 Eip7702(TxEip7702),
555 }
556
557 impl<Eip4844> From<MaybeTaggedTypedTransaction<Eip4844>> for EthereumTypedTransaction<Eip4844> {
558 fn from(value: MaybeTaggedTypedTransaction<Eip4844>) -> Self {
559 match value {
560 MaybeTaggedTypedTransaction::Tagged(tagged) => tagged.into(),
561 MaybeTaggedTypedTransaction::Untagged { tx, .. } => Self::Legacy(tx),
562 }
563 }
564 }
565
566 impl<Eip4844> From<TaggedTypedTransaction<Eip4844>> for EthereumTypedTransaction<Eip4844> {
567 fn from(value: TaggedTypedTransaction<Eip4844>) -> Self {
568 match value {
569 TaggedTypedTransaction::Legacy(signed) => Self::Legacy(signed),
570 TaggedTypedTransaction::Eip2930(signed) => Self::Eip2930(signed),
571 TaggedTypedTransaction::Eip1559(signed) => Self::Eip1559(signed),
572 TaggedTypedTransaction::Eip4844(signed) => Self::Eip4844(signed),
573 TaggedTypedTransaction::Eip7702(signed) => Self::Eip7702(signed),
574 }
575 }
576 }
577
578 impl<Eip4844> From<EthereumTypedTransaction<Eip4844>> for TaggedTypedTransaction<Eip4844> {
579 fn from(value: EthereumTypedTransaction<Eip4844>) -> Self {
580 match value {
581 EthereumTypedTransaction::Legacy(signed) => Self::Legacy(signed),
582 EthereumTypedTransaction::Eip2930(signed) => Self::Eip2930(signed),
583 EthereumTypedTransaction::Eip1559(signed) => Self::Eip1559(signed),
584 EthereumTypedTransaction::Eip4844(signed) => Self::Eip4844(signed),
585 EthereumTypedTransaction::Eip7702(signed) => Self::Eip7702(signed),
586 }
587 }
588 }
589}
590
591#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
593pub(crate) mod serde_bincode_compat {
594 use alloc::borrow::Cow;
595 use serde::{Deserialize, Deserializer, Serialize, Serializer};
596 use serde_with::{DeserializeAs, SerializeAs};
597
598 #[derive(Debug, Serialize, Deserialize)]
614 pub enum EthereumTypedTransaction<'a, Eip4844: Clone = crate::transaction::TxEip4844> {
615 Legacy(crate::serde_bincode_compat::transaction::TxLegacy<'a>),
617 Eip2930(crate::serde_bincode_compat::transaction::TxEip2930<'a>),
619 Eip1559(crate::serde_bincode_compat::transaction::TxEip1559<'a>),
621 Eip4844(Cow<'a, Eip4844>),
625 Eip7702(crate::serde_bincode_compat::transaction::TxEip7702<'a>),
627 }
628
629 impl<'a, T: Clone> From<&'a super::EthereumTypedTransaction<T>>
630 for EthereumTypedTransaction<'a, T>
631 {
632 fn from(value: &'a super::EthereumTypedTransaction<T>) -> Self {
633 match value {
634 super::EthereumTypedTransaction::Legacy(tx) => Self::Legacy(tx.into()),
635 super::EthereumTypedTransaction::Eip2930(tx) => Self::Eip2930(tx.into()),
636 super::EthereumTypedTransaction::Eip1559(tx) => Self::Eip1559(tx.into()),
637 super::EthereumTypedTransaction::Eip4844(tx) => Self::Eip4844(Cow::Borrowed(tx)),
638 super::EthereumTypedTransaction::Eip7702(tx) => Self::Eip7702(tx.into()),
639 }
640 }
641 }
642
643 impl<'a, T: Clone> From<EthereumTypedTransaction<'a, T>> for super::EthereumTypedTransaction<T> {
644 fn from(value: EthereumTypedTransaction<'a, T>) -> Self {
645 match value {
646 EthereumTypedTransaction::Legacy(tx) => Self::Legacy(tx.into()),
647 EthereumTypedTransaction::Eip2930(tx) => Self::Eip2930(tx.into()),
648 EthereumTypedTransaction::Eip1559(tx) => Self::Eip1559(tx.into()),
649 EthereumTypedTransaction::Eip4844(tx) => Self::Eip4844(tx.into_owned()),
650 EthereumTypedTransaction::Eip7702(tx) => Self::Eip7702(tx.into()),
651 }
652 }
653 }
654
655 impl<T: Serialize + Clone> SerializeAs<super::EthereumTypedTransaction<T>>
656 for EthereumTypedTransaction<'_, T>
657 {
658 fn serialize_as<S>(
659 source: &super::EthereumTypedTransaction<T>,
660 serializer: S,
661 ) -> Result<S::Ok, S::Error>
662 where
663 S: Serializer,
664 {
665 EthereumTypedTransaction::<'_, T>::from(source).serialize(serializer)
666 }
667 }
668
669 impl<'de, T: Deserialize<'de> + Clone> DeserializeAs<'de, super::EthereumTypedTransaction<T>>
670 for EthereumTypedTransaction<'de, T>
671 {
672 fn deserialize_as<D>(
673 deserializer: D,
674 ) -> Result<super::EthereumTypedTransaction<T>, D::Error>
675 where
676 D: Deserializer<'de>,
677 {
678 EthereumTypedTransaction::<'_, T>::deserialize(deserializer).map(Into::into)
679 }
680 }
681
682 #[cfg(test)]
683 mod tests {
684 use super::super::{serde_bincode_compat, EthereumTypedTransaction};
685 use crate::TxEip4844;
686 use arbitrary::Arbitrary;
687 use bincode::config;
688 use rand::Rng;
689 use serde::{Deserialize, Serialize};
690 use serde_with::serde_as;
691
692 #[test]
693 fn test_typed_tx_bincode_roundtrip() {
694 #[serde_as]
695 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
696 struct Data {
697 #[serde_as(as = "serde_bincode_compat::EthereumTypedTransaction<'_>")]
698 transaction: EthereumTypedTransaction<TxEip4844>,
699 }
700
701 let mut bytes = [0u8; 1024];
702 rand::thread_rng().fill(bytes.as_mut_slice());
703 let data = Data {
704 transaction: EthereumTypedTransaction::arbitrary(
705 &mut arbitrary::Unstructured::new(&bytes),
706 )
707 .unwrap(),
708 };
709
710 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
711 let (decoded, _) =
712 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
713 assert_eq!(decoded, data);
714 }
715 }
716}