1use super::*;
21use alloc::vec::Vec;
22use rlp::{Decodable, Encodable};
23
24impl TransactionUnsigned {
25 pub fn unsigned_payload(&self) -> Vec<u8> {
27 use TransactionUnsigned::*;
28 let mut s = rlp::RlpStream::new();
29 match self {
30 Transaction7702Unsigned(tx) => {
31 s.append(&tx.r#type.value());
32 s.append(tx);
33 },
34 Transaction2930Unsigned(tx) => {
35 s.append(&tx.r#type.value());
36 s.append(tx);
37 },
38 Transaction1559Unsigned(tx) => {
39 s.append(&tx.r#type.value());
40 s.append(tx);
41 },
42 Transaction4844Unsigned(tx) => {
43 s.append(&tx.r#type.value());
44 s.append(tx);
45 },
46 TransactionLegacyUnsigned(tx) => {
47 s.append(tx);
48 },
49 }
50
51 s.out().to_vec()
52 }
53}
54
55impl TransactionSigned {
56 pub fn unsigned(self) -> TransactionUnsigned {
58 use TransactionSigned::*;
59 use TransactionUnsigned::*;
60 match self {
61 Transaction7702Signed(tx) => Transaction7702Unsigned(tx.transaction_7702_unsigned),
62 Transaction2930Signed(tx) => Transaction2930Unsigned(tx.transaction_2930_unsigned),
63 Transaction1559Signed(tx) => Transaction1559Unsigned(tx.transaction_1559_unsigned),
64 Transaction4844Signed(tx) => Transaction4844Unsigned(tx.transaction_4844_unsigned),
65 TransactionLegacySigned(tx) => {
66 TransactionLegacyUnsigned(tx.transaction_legacy_unsigned)
67 },
68 }
69 }
70
71 pub fn signed_payload(&self) -> Vec<u8> {
73 use TransactionSigned::*;
74 let mut s = rlp::RlpStream::new();
75 match self {
76 Transaction7702Signed(tx) => {
77 s.append(&tx.transaction_7702_unsigned.r#type.value());
78 s.append(tx);
79 },
80 Transaction2930Signed(tx) => {
81 s.append(&tx.transaction_2930_unsigned.r#type.value());
82 s.append(tx);
83 },
84 Transaction1559Signed(tx) => {
85 s.append(&tx.transaction_1559_unsigned.r#type.value());
86 s.append(tx);
87 },
88 Transaction4844Signed(tx) => {
89 s.append(&tx.transaction_4844_unsigned.r#type.value());
90 s.append(tx);
91 },
92 TransactionLegacySigned(tx) => {
93 s.append(tx);
94 },
95 }
96
97 s.out().to_vec()
98 }
99
100 pub fn decode(data: &[u8]) -> Result<Self, rlp::DecoderError> {
102 if data.is_empty() {
103 return Err(rlp::DecoderError::RlpIsTooShort);
104 }
105 let first_byte = data[0];
106
107 if first_byte <= 0x7f {
109 match first_byte {
110 TYPE_EIP2930 => rlp::decode::<Transaction2930Signed>(&data[1..]).map(Into::into),
111 TYPE_EIP1559 => rlp::decode::<Transaction1559Signed>(&data[1..]).map(Into::into),
112 TYPE_EIP4844 => rlp::decode::<Transaction4844Signed>(&data[1..]).map(Into::into),
113 TYPE_EIP7702 => rlp::decode::<Transaction7702Signed>(&data[1..]).map(Into::into),
114 _ => Err(rlp::DecoderError::Custom("Unknown transaction type")),
115 }
116 } else {
117 rlp::decode::<TransactionLegacySigned>(data).map(Into::into)
118 }
119 }
120}
121
122impl TransactionUnsigned {
123 pub fn dummy_signed_payload(self) -> Vec<u8> {
125 const DUMMY_SIGNATURE: [u8; 65] = [1u8; 65];
126 self.with_signature(DUMMY_SIGNATURE).signed_payload()
127 }
128}
129
130impl Encodable for TransactionLegacyUnsigned {
132 fn rlp_append(&self, s: &mut rlp::RlpStream) {
133 if let Some(chain_id) = self.chain_id {
134 s.begin_list(9);
135 s.append(&self.nonce);
136 s.append(&self.gas_price);
137 s.append(&self.gas);
138 match self.to {
139 Some(ref to) => s.append(to),
140 None => s.append_empty_data(),
141 };
142 s.append(&self.value);
143 s.append(&self.input.0);
144 s.append(&chain_id);
145 s.append(&0u8);
146 s.append(&0u8);
147 } else {
148 s.begin_list(6);
149 s.append(&self.nonce);
150 s.append(&self.gas_price);
151 s.append(&self.gas);
152 match self.to {
153 Some(ref to) => s.append(to),
154 None => s.append_empty_data(),
155 };
156 s.append(&self.value);
157 s.append(&self.input.0);
158 }
159 }
160}
161
162impl Decodable for TransactionLegacyUnsigned {
163 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
164 Ok(TransactionLegacyUnsigned {
165 nonce: rlp.val_at(0)?,
166 gas_price: rlp.val_at(1)?,
167 gas: rlp.val_at(2)?,
168 to: {
169 let to = rlp.at(3)?;
170 if to.is_empty() { None } else { Some(to.as_val()?) }
171 },
172 value: rlp.val_at(4)?,
173 input: Bytes(rlp.val_at(5)?),
174 chain_id: rlp.val_at(6).ok(),
175 ..Default::default()
176 })
177 }
178}
179
180impl Encodable for TransactionLegacySigned {
181 fn rlp_append(&self, s: &mut rlp::RlpStream) {
182 let tx = &self.transaction_legacy_unsigned;
183
184 s.begin_list(9);
185 s.append(&tx.nonce);
186 s.append(&tx.gas_price);
187 s.append(&tx.gas);
188 match tx.to {
189 Some(ref to) => s.append(to),
190 None => s.append_empty_data(),
191 };
192 s.append(&tx.value);
193 s.append(&tx.input.0);
194
195 s.append(&self.v);
196 s.append(&self.r);
197 s.append(&self.s);
198 }
199}
200
201impl Encodable for AccessListEntry {
202 fn rlp_append(&self, s: &mut rlp::RlpStream) {
203 s.begin_list(2);
204 s.append(&self.address);
205 s.append_list(&self.storage_keys);
206 }
207}
208
209impl Decodable for AccessListEntry {
210 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
211 Ok(AccessListEntry { address: rlp.val_at(0)?, storage_keys: rlp.list_at(1)? })
212 }
213}
214
215impl Encodable for AuthorizationListEntry {
216 fn rlp_append(&self, s: &mut rlp::RlpStream) {
217 s.begin_list(6);
218 s.append(&self.chain_id);
219 s.append(&self.address);
220 s.append(&self.nonce);
221 s.append(&self.y_parity);
222 s.append(&self.r);
223 s.append(&self.s);
224 }
225}
226
227impl Decodable for AuthorizationListEntry {
228 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
229 Ok(AuthorizationListEntry {
230 chain_id: rlp.val_at(0)?,
231 address: rlp.val_at(1)?,
232 nonce: rlp.val_at(2)?,
233 y_parity: rlp.val_at(3)?,
234 r: rlp.val_at(4)?,
235 s: rlp.val_at(5)?,
236 })
237 }
238}
239
240impl AuthorizationListEntry {
241 pub fn rlp_encode_unsigned(&self) -> Vec<u8> {
243 let mut s = rlp::RlpStream::new_list(3);
244 s.append(&self.chain_id);
245 s.append(&self.address);
246 s.append(&self.nonce);
247 s.out().to_vec()
248 }
249}
250
251impl Encodable for Transaction1559Unsigned {
253 fn rlp_append(&self, s: &mut rlp::RlpStream) {
254 s.begin_list(9);
255 s.append(&self.chain_id);
256 s.append(&self.nonce);
257 s.append(&self.max_priority_fee_per_gas);
258 s.append(&self.max_fee_per_gas);
259 s.append(&self.gas);
260 match self.to {
261 Some(ref to) => s.append(to),
262 None => s.append_empty_data(),
263 };
264 s.append(&self.value);
265 s.append(&self.input.0);
266 s.append_list(&self.access_list);
267 }
268}
269
270impl Encodable for Transaction1559Signed {
272 fn rlp_append(&self, s: &mut rlp::RlpStream) {
273 let tx = &self.transaction_1559_unsigned;
274 s.begin_list(12);
275 s.append(&tx.chain_id);
276 s.append(&tx.nonce);
277 s.append(&tx.max_priority_fee_per_gas);
278 s.append(&tx.max_fee_per_gas);
279 s.append(&tx.gas);
280 match tx.to {
281 Some(ref to) => s.append(to),
282 None => s.append_empty_data(),
283 };
284 s.append(&tx.value);
285 s.append(&tx.input.0);
286 s.append_list(&tx.access_list);
287
288 s.append(&self.y_parity);
289 s.append(&self.r);
290 s.append(&self.s);
291 }
292}
293
294impl Decodable for Transaction1559Signed {
295 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
296 Ok(Transaction1559Signed {
297 transaction_1559_unsigned: {
298 Transaction1559Unsigned {
299 chain_id: rlp.val_at(0)?,
300 nonce: rlp.val_at(1)?,
301 max_priority_fee_per_gas: rlp.val_at(2)?,
302 max_fee_per_gas: rlp.val_at(3)?,
303 gas: rlp.val_at(4)?,
304 to: {
305 let to = rlp.at(5)?;
306 if to.is_empty() { None } else { Some(to.as_val()?) }
307 },
308 value: rlp.val_at(6)?,
309 input: Bytes(rlp.val_at(7)?),
310 access_list: rlp.list_at(8)?,
311 ..Default::default()
312 }
313 },
314 y_parity: rlp.val_at(9)?,
315 r: rlp.val_at(10)?,
316 s: rlp.val_at(11)?,
317 ..Default::default()
318 })
319 }
320}
321
322impl Encodable for Transaction2930Unsigned {
324 fn rlp_append(&self, s: &mut rlp::RlpStream) {
325 s.begin_list(8);
326 s.append(&self.chain_id);
327 s.append(&self.nonce);
328 s.append(&self.gas_price);
329 s.append(&self.gas);
330 match self.to {
331 Some(ref to) => s.append(to),
332 None => s.append_empty_data(),
333 };
334 s.append(&self.value);
335 s.append(&self.input.0);
336 s.append_list(&self.access_list);
337 }
338}
339
340impl Encodable for Transaction2930Signed {
342 fn rlp_append(&self, s: &mut rlp::RlpStream) {
343 let tx = &self.transaction_2930_unsigned;
344 s.begin_list(11);
345 s.append(&tx.chain_id);
346 s.append(&tx.nonce);
347 s.append(&tx.gas_price);
348 s.append(&tx.gas);
349 match tx.to {
350 Some(ref to) => s.append(to),
351 None => s.append_empty_data(),
352 };
353 s.append(&tx.value);
354 s.append(&tx.input.0);
355 s.append_list(&tx.access_list);
356 s.append(&self.y_parity);
357 s.append(&self.r);
358 s.append(&self.s);
359 }
360}
361
362impl Decodable for Transaction2930Signed {
363 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
364 Ok(Transaction2930Signed {
365 transaction_2930_unsigned: {
366 Transaction2930Unsigned {
367 chain_id: rlp.val_at(0)?,
368 nonce: rlp.val_at(1)?,
369 gas_price: rlp.val_at(2)?,
370 gas: rlp.val_at(3)?,
371 to: {
372 let to = rlp.at(4)?;
373 if to.is_empty() { None } else { Some(to.as_val()?) }
374 },
375 value: rlp.val_at(5)?,
376 input: Bytes(rlp.val_at(6)?),
377 access_list: rlp.list_at(7)?,
378 ..Default::default()
379 }
380 },
381 y_parity: rlp.val_at(8)?,
382 r: rlp.val_at(9)?,
383 s: rlp.val_at(10)?,
384 ..Default::default()
385 })
386 }
387}
388
389impl Encodable for Transaction7702Unsigned {
391 fn rlp_append(&self, s: &mut rlp::RlpStream) {
392 s.begin_list(10);
393 s.append(&self.chain_id);
394 s.append(&self.nonce);
395 s.append(&self.max_priority_fee_per_gas);
396 s.append(&self.max_fee_per_gas);
397 s.append(&self.gas);
398 s.append(&self.to);
399 s.append(&self.value);
400 s.append(&self.input.0);
401 s.append_list(&self.access_list);
402 s.append_list(&self.authorization_list);
403 }
404}
405
406impl Decodable for Transaction7702Signed {
407 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
408 Ok(Transaction7702Signed {
409 transaction_7702_unsigned: {
410 Transaction7702Unsigned {
411 chain_id: rlp.val_at(0)?,
412 nonce: rlp.val_at(1)?,
413 max_priority_fee_per_gas: rlp.val_at(2)?,
414 max_fee_per_gas: rlp.val_at(3)?,
415 gas: rlp.val_at(4)?,
416 to: rlp.val_at(5)?,
417 value: rlp.val_at(6)?,
418 input: Bytes(rlp.val_at(7)?),
419 access_list: rlp.list_at(8)?,
420 authorization_list: rlp.list_at(9)?,
421 r#type: Default::default(),
422 }
423 },
424 y_parity: rlp.val_at(10)?,
425 r: rlp.val_at(11)?,
426 s: rlp.val_at(12)?,
427 v: None,
428 })
429 }
430}
431
432impl Encodable for Transaction4844Unsigned {
433 fn rlp_append(&self, s: &mut rlp::RlpStream) {
434 s.begin_list(11);
435 s.append(&self.chain_id);
436 s.append(&self.nonce);
437 s.append(&self.max_priority_fee_per_gas);
438 s.append(&self.max_fee_per_gas);
439 s.append(&self.gas);
440 s.append(&self.to);
441 s.append(&self.value);
442 s.append(&self.input.0);
443 s.append_list(&self.access_list);
444 s.append(&self.max_fee_per_blob_gas);
445 s.append_list(&self.blob_versioned_hashes);
446 }
447}
448
449impl Encodable for Transaction7702Signed {
451 fn rlp_append(&self, s: &mut rlp::RlpStream) {
452 let tx = &self.transaction_7702_unsigned;
453 s.begin_list(13);
454 s.append(&tx.chain_id);
455 s.append(&tx.nonce);
456 s.append(&tx.max_priority_fee_per_gas);
457 s.append(&tx.max_fee_per_gas);
458 s.append(&tx.gas);
459 s.append(&tx.to);
460 s.append(&tx.value);
461 s.append(&tx.input.0);
462 s.append_list(&tx.access_list);
463 s.append_list(&tx.authorization_list);
464 s.append(&self.y_parity);
465 s.append(&self.r);
466 s.append(&self.s);
467 }
468}
469
470impl Encodable for Transaction4844Signed {
472 fn rlp_append(&self, s: &mut rlp::RlpStream) {
473 let tx = &self.transaction_4844_unsigned;
474 s.begin_list(14);
475 s.append(&tx.chain_id);
476 s.append(&tx.nonce);
477 s.append(&tx.max_priority_fee_per_gas);
478 s.append(&tx.max_fee_per_gas);
479 s.append(&tx.gas);
480 s.append(&tx.to);
481 s.append(&tx.value);
482 s.append(&tx.input.0);
483 s.append_list(&tx.access_list);
484 s.append(&tx.max_fee_per_blob_gas);
485 s.append_list(&tx.blob_versioned_hashes);
486 s.append(&self.y_parity);
487 s.append(&self.r);
488 s.append(&self.s);
489 }
490}
491
492impl Decodable for Transaction4844Signed {
493 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
494 Ok(Transaction4844Signed {
495 transaction_4844_unsigned: {
496 Transaction4844Unsigned {
497 chain_id: rlp.val_at(0)?,
498 nonce: rlp.val_at(1)?,
499 max_priority_fee_per_gas: rlp.val_at(2)?,
500 max_fee_per_gas: rlp.val_at(3)?,
501 gas: rlp.val_at(4)?,
502 to: rlp.val_at(5)?,
503 value: rlp.val_at(6)?,
504 input: Bytes(rlp.val_at(7)?),
505 access_list: rlp.list_at(8)?,
506 max_fee_per_blob_gas: rlp.val_at(9)?,
507 blob_versioned_hashes: rlp.list_at(10)?,
508 ..Default::default()
509 }
510 },
511 y_parity: rlp.val_at(11)?,
512 r: rlp.val_at(12)?,
513 s: rlp.val_at(13)?,
514 })
515 }
516}
517
518impl Decodable for TransactionLegacySigned {
520 fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
521 let v: U256 = rlp.val_at(6)?;
522
523 let extract_chain_id = |v: U256| {
524 if v.ge(&35u32.into()) { Some((v - 35) / 2) } else { None }
525 };
526
527 Ok(TransactionLegacySigned {
528 transaction_legacy_unsigned: {
529 TransactionLegacyUnsigned {
530 nonce: rlp.val_at(0)?,
531 gas_price: rlp.val_at(1)?,
532 gas: rlp.val_at(2)?,
533 to: {
534 let to = rlp.at(3)?;
535 if to.is_empty() { None } else { Some(to.as_val()?) }
536 },
537 value: rlp.val_at(4)?,
538 input: Bytes(rlp.val_at(5)?),
539 chain_id: extract_chain_id(v).map(|v| v.into()),
540 r#type: TypeLegacy {},
541 }
542 },
543 v,
544 r: rlp.val_at(7)?,
545 s: rlp.val_at(8)?,
546 })
547 }
548}
549
550#[cfg(test)]
551mod test {
552 use super::*;
553
554 #[test]
555 fn encode_decode_tx_works() {
556 let txs = [
557 (
559 "f86080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d87808025a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
560 r#"
561 {
562 "chainId": "0x1",
563 "gas": "0x1e241",
564 "gasPrice": "0x0",
565 "input": "0x",
566 "nonce": "0x0",
567 "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87",
568 "type": "0x0",
569 "value": "0x0",
570 "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0",
571 "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
572 "v": "0x25"
573 }
574 "#,
575 ),
576 (
578 "01f89b0180808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
579 r#"
580 {
581 "accessList": [
582 {
583 "address": "0x0000000000000000000000000000000000000001",
584 "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
585 }
586 ],
587 "chainId": "0x1",
588 "gas": "0x1e241",
589 "gasPrice": "0x0",
590 "input": "0x",
591 "nonce": "0x0",
592 "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87",
593 "type": "0x1",
594 "value": "0x0",
595 "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0",
596 "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
597 "yParity": "0x0"
598 }
599 "#,
600 ),
601 (
603 "02f89c018080018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
604 r#"
605 {
606 "accessList": [
607 {
608 "address": "0x0000000000000000000000000000000000000001",
609 "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
610 }
611 ],
612 "chainId": "0x1",
613 "gas": "0x1e241",
614 "gasPrice": "0x0",
615 "input": "0x",
616 "maxFeePerGas": "0x1",
617 "maxPriorityFeePerGas": "0x0",
618 "nonce": "0x0",
619 "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87",
620 "type": "0x2",
621 "value": "0x0",
622 "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0",
623 "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
624 "yParity": "0x0"
625
626 }
627 "#,
628 ),
629 (
631 "03f8bf018002018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
632 r#"
633 {
634 "accessList": [
635 {
636 "address": "0x0000000000000000000000000000000000000001",
637 "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
638 }
639 ],
640 "blobVersionedHashes": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
641 "chainId": "0x1",
642 "gas": "0x1e241",
643 "input": "0x",
644 "maxFeePerBlobGas": "0x0",
645 "maxFeePerGas": "0x1",
646 "maxPriorityFeePerGas": "0x2",
647 "nonce": "0x0",
648 "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87",
649 "type": "0x3",
650 "value": "0x0",
651 "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0",
652 "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
653 "yParity": "0x0"
654 }
655 "#,
656 ),
657 ];
658
659 for (tx, json) in txs {
660 let raw_tx = alloy_core::hex::decode(tx).unwrap();
661 let tx = TransactionSigned::decode(&raw_tx).unwrap();
662 assert_eq!(tx.signed_payload(), raw_tx);
663 let expected_tx =
664 serde_json::from_str::<pallet_revive_types::runtime_api::TransactionSignedV1>(json)
665 .unwrap();
666 assert_eq!(
667 pallet_revive_types::runtime_api::TransactionSignedV1::from(tx),
668 expected_tx
669 );
670 }
671 }
672
673 #[test]
674 fn encode_decode_7702_tx_works() {
675 let tx = TransactionSigned::Transaction7702Signed(Transaction7702Signed {
676 transaction_7702_unsigned: Transaction7702Unsigned {
677 chain_id: U256::from(1),
678 nonce: U256::zero(),
679 max_priority_fee_per_gas: U256::zero(),
680 max_fee_per_gas: U256::from(1),
681 gas: U256::from(0x1e241),
682 to: "0x095e7baea6a6c7c4c2dfeb977efac326af552d87".parse().unwrap(),
683 value: U256::zero(),
684 input: Bytes(vec![]),
685 access_list: vec![AccessListEntry {
686 address: H160::from_low_u64_be(1),
687 storage_keys: vec![H256::zero()],
688 }],
689 authorization_list: vec![AuthorizationListEntry {
690 chain_id: U256::from(1),
691 address: H160::from_low_u64_be(42),
692 nonce: U256::zero(),
693 y_parity: U256::zero(),
694 r: U256::from(1),
695 s: U256::from(2),
696 }],
697 r#type: TypeEip7702 {},
698 },
699 y_parity: U256::zero(),
700 r: U256::from(1),
701 s: U256::from(2),
702 v: None,
703 });
704
705 let encoded = tx.signed_payload();
706 let decoded = TransactionSigned::decode(&encoded).unwrap();
707 assert_eq!(tx, decoded);
708 }
709
710 #[test]
711 fn dummy_signed_payload_works() {
712 let tx: TransactionUnsigned = TransactionLegacyUnsigned {
713 chain_id: Some(596.into()),
714 gas: U256::from(21000),
715 nonce: U256::from(1),
716 gas_price: U256::from("0x640000006a"),
717 to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()),
718 value: U256::from(123123),
719 input: Bytes(vec![]),
720 r#type: TypeLegacy,
721 }
722 .into();
723
724 let dummy_signed_payload = tx.clone().dummy_signed_payload();
725 let payload = Account::default().sign_transaction(tx).signed_payload();
726 assert_eq!(dummy_signed_payload.len(), payload.len());
727 }
728
729 #[test]
730 fn rlp_codec_is_compatible_with_ethereum() {
731 let test_cases = [
733 "f86080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d87808025a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
735 "01f89b0180808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
737 "02f89c018080018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8",
739 "03f89783aa36a701832dc6c083fc546c8261a8947f8b1ca29f95274e06367b60fc4a539e4910fd0c865af3107a400080c0831e8480e1a0018fd423d1ad106395f04abac797217d4dece29da3ba649d9aa4da70e98fa6ff80a028d2350a1bfa5043de1533911143eb5c43815a58039121a0ccf124870620fca6a0157eca4963615cd3926538af88e529cfa3baf6c55787a33f79c25babe9f5db2b",
741 ];
742
743 for hex_tx in test_cases {
744 let rlp_encoded_tx = alloy_core::hex::decode(hex_tx).unwrap();
745
746 let tx_revive = TransactionSigned::decode(&rlp_encoded_tx).unwrap();
748
749 let rlp_encoded_revive = tx_revive.signed_payload();
751
752 assert_eq!(rlp_encoded_tx, rlp_encoded_revive);
754 }
755 }
756}