|
2 | 2 | use alloy_consensus::{ |
3 | 3 | Receipt, ReceiptEnvelope, ReceiptWithBloom, Signed, Transaction, TxEip1559, TxEip2930, |
4 | 4 | TxEnvelope, TxLegacy, TxReceipt, Typed2718, |
5 | | - constants::{ |
6 | | - EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, |
7 | | - LEGACY_TX_TYPE_ID, |
8 | | - }, |
9 | 5 | transaction::{ |
10 | 6 | Recovered, TxEip7702, |
11 | 7 | eip4844::{TxEip4844, TxEip4844Variant, TxEip4844WithSidecar}, |
12 | 8 | }, |
13 | 9 | }; |
14 | 10 |
|
15 | 11 | use alloy_eips::eip2718::{Decodable2718, Eip2718Error, Encodable2718}; |
| 12 | +use alloy_evm::FromRecoveredTx; |
16 | 13 | use alloy_network::{AnyReceiptEnvelope, AnyRpcTransaction, AnyTransactionReceipt, AnyTxEnvelope}; |
17 | 14 | use alloy_primitives::{Address, B256, Bloom, Bytes, Signature, TxHash, TxKind, U64, U256}; |
18 | 15 | use alloy_rlp::{Decodable, Encodable, Header}; |
@@ -388,196 +385,6 @@ impl PendingTransaction { |
388 | 385 | pub fn sender(&self) -> &Address { |
389 | 386 | &self.sender |
390 | 387 | } |
391 | | - |
392 | | - /// Converts the [PendingTransaction] into the [TxEnv] context that [`revm`](foundry_evm) |
393 | | - /// expects. |
394 | | - /// |
395 | | - /// Base [`TxEnv`] is encapsulated in the [`op_revm::OpTransaction`] |
396 | | - pub fn to_revm_tx_env(&self) -> OpTransaction<TxEnv> { |
397 | | - fn transact_to(kind: &TxKind) -> TxKind { |
398 | | - match kind { |
399 | | - TxKind::Call(c) => TxKind::Call(*c), |
400 | | - TxKind::Create => TxKind::Create, |
401 | | - } |
402 | | - } |
403 | | - |
404 | | - let caller = *self.sender(); |
405 | | - match &self.transaction.transaction { |
406 | | - TypedTransaction::Legacy(tx) => { |
407 | | - let chain_id = tx.tx().chain_id; |
408 | | - let TxLegacy { nonce, gas_price, gas_limit, value, to, input, .. } = tx.tx(); |
409 | | - OpTransaction::new(TxEnv { |
410 | | - caller, |
411 | | - kind: transact_to(to), |
412 | | - data: input.clone(), |
413 | | - chain_id, |
414 | | - nonce: *nonce, |
415 | | - value: (*value), |
416 | | - gas_price: *gas_price, |
417 | | - gas_priority_fee: None, |
418 | | - gas_limit: *gas_limit, |
419 | | - access_list: vec![].into(), |
420 | | - tx_type: LEGACY_TX_TYPE_ID, |
421 | | - ..Default::default() |
422 | | - }) |
423 | | - } |
424 | | - TypedTransaction::EIP2930(tx) => { |
425 | | - let TxEip2930 { |
426 | | - chain_id, |
427 | | - nonce, |
428 | | - gas_price, |
429 | | - gas_limit, |
430 | | - to, |
431 | | - value, |
432 | | - input, |
433 | | - access_list, |
434 | | - .. |
435 | | - } = tx.tx(); |
436 | | - OpTransaction::new(TxEnv { |
437 | | - caller, |
438 | | - kind: transact_to(to), |
439 | | - data: input.clone(), |
440 | | - chain_id: Some(*chain_id), |
441 | | - nonce: *nonce, |
442 | | - value: *value, |
443 | | - gas_price: *gas_price, |
444 | | - gas_priority_fee: None, |
445 | | - gas_limit: *gas_limit, |
446 | | - access_list: access_list.clone(), |
447 | | - tx_type: EIP2930_TX_TYPE_ID, |
448 | | - ..Default::default() |
449 | | - }) |
450 | | - } |
451 | | - TypedTransaction::EIP1559(tx) => { |
452 | | - let TxEip1559 { |
453 | | - chain_id, |
454 | | - nonce, |
455 | | - max_priority_fee_per_gas, |
456 | | - max_fee_per_gas, |
457 | | - gas_limit, |
458 | | - to, |
459 | | - value, |
460 | | - input, |
461 | | - access_list, |
462 | | - .. |
463 | | - } = tx.tx(); |
464 | | - OpTransaction::new(TxEnv { |
465 | | - caller, |
466 | | - kind: transact_to(to), |
467 | | - data: input.clone(), |
468 | | - chain_id: Some(*chain_id), |
469 | | - nonce: *nonce, |
470 | | - value: *value, |
471 | | - gas_price: *max_fee_per_gas, |
472 | | - gas_priority_fee: Some(*max_priority_fee_per_gas), |
473 | | - gas_limit: *gas_limit, |
474 | | - access_list: access_list.clone(), |
475 | | - tx_type: EIP1559_TX_TYPE_ID, |
476 | | - ..Default::default() |
477 | | - }) |
478 | | - } |
479 | | - TypedTransaction::EIP4844(tx) => { |
480 | | - let TxEip4844 { |
481 | | - chain_id, |
482 | | - nonce, |
483 | | - max_fee_per_blob_gas, |
484 | | - max_fee_per_gas, |
485 | | - max_priority_fee_per_gas, |
486 | | - gas_limit, |
487 | | - to, |
488 | | - value, |
489 | | - input, |
490 | | - access_list, |
491 | | - blob_versioned_hashes, |
492 | | - .. |
493 | | - } = tx.tx().tx(); |
494 | | - OpTransaction::new(TxEnv { |
495 | | - caller, |
496 | | - kind: TxKind::Call(*to), |
497 | | - data: input.clone(), |
498 | | - chain_id: Some(*chain_id), |
499 | | - nonce: *nonce, |
500 | | - value: *value, |
501 | | - gas_price: *max_fee_per_gas, |
502 | | - gas_priority_fee: Some(*max_priority_fee_per_gas), |
503 | | - max_fee_per_blob_gas: *max_fee_per_blob_gas, |
504 | | - blob_hashes: blob_versioned_hashes.clone(), |
505 | | - gas_limit: *gas_limit, |
506 | | - access_list: access_list.clone(), |
507 | | - tx_type: EIP4844_TX_TYPE_ID, |
508 | | - ..Default::default() |
509 | | - }) |
510 | | - } |
511 | | - TypedTransaction::EIP7702(tx) => { |
512 | | - let TxEip7702 { |
513 | | - chain_id, |
514 | | - nonce, |
515 | | - gas_limit, |
516 | | - max_fee_per_gas, |
517 | | - max_priority_fee_per_gas, |
518 | | - to, |
519 | | - value, |
520 | | - access_list, |
521 | | - authorization_list, |
522 | | - input, |
523 | | - } = tx.tx(); |
524 | | - |
525 | | - let mut tx = TxEnv { |
526 | | - caller, |
527 | | - kind: TxKind::Call(*to), |
528 | | - data: input.clone(), |
529 | | - chain_id: Some(*chain_id), |
530 | | - nonce: *nonce, |
531 | | - value: *value, |
532 | | - gas_price: *max_fee_per_gas, |
533 | | - gas_priority_fee: Some(*max_priority_fee_per_gas), |
534 | | - gas_limit: *gas_limit, |
535 | | - access_list: access_list.clone(), |
536 | | - tx_type: EIP7702_TX_TYPE_ID, |
537 | | - ..Default::default() |
538 | | - }; |
539 | | - tx.set_signed_authorization(authorization_list.clone()); |
540 | | - |
541 | | - OpTransaction::new(tx) |
542 | | - } |
543 | | - TypedTransaction::Deposit(tx) => { |
544 | | - let chain_id = tx.chain_id(); |
545 | | - let TxDeposit { |
546 | | - source_hash, |
547 | | - to, |
548 | | - mint, |
549 | | - value, |
550 | | - gas_limit, |
551 | | - is_system_transaction, |
552 | | - input, |
553 | | - .. |
554 | | - } = tx; |
555 | | - |
556 | | - let base = TxEnv { |
557 | | - caller, |
558 | | - kind: transact_to(to), |
559 | | - data: input.clone(), |
560 | | - chain_id, |
561 | | - nonce: 0, |
562 | | - value: *value, |
563 | | - gas_price: 0, |
564 | | - gas_priority_fee: None, |
565 | | - gas_limit: { *gas_limit }, |
566 | | - access_list: vec![].into(), |
567 | | - tx_type: DEPOSIT_TX_TYPE_ID, |
568 | | - ..Default::default() |
569 | | - }; |
570 | | - |
571 | | - let deposit = DepositTransactionParts { |
572 | | - source_hash: *source_hash, |
573 | | - mint: Some(*mint), |
574 | | - is_system_transaction: *is_system_transaction, |
575 | | - }; |
576 | | - |
577 | | - OpTransaction { base, deposit, enveloped_tx: None } |
578 | | - } |
579 | | - } |
580 | | - } |
581 | 388 | } |
582 | 389 |
|
583 | 390 | /// Container type for signed, typed transactions. |
@@ -1539,6 +1346,39 @@ pub fn convert_to_anvil_receipt(receipt: AnyTransactionReceipt) -> Option<Receip |
1539 | 1346 | }) |
1540 | 1347 | } |
1541 | 1348 |
|
| 1349 | +impl FromRecoveredTx<TypedTransaction> for TxEnv { |
| 1350 | + fn from_recovered_tx(tx: &TypedTransaction, caller: Address) -> Self { |
| 1351 | + match tx { |
| 1352 | + TypedTransaction::Legacy(signed_tx) => Self::from_recovered_tx(signed_tx.tx(), caller), |
| 1353 | + TypedTransaction::EIP2930(signed_tx) => Self::from_recovered_tx(signed_tx.tx(), caller), |
| 1354 | + TypedTransaction::EIP1559(signed_tx) => Self::from_recovered_tx(signed_tx.tx(), caller), |
| 1355 | + TypedTransaction::EIP4844(signed_tx) => { |
| 1356 | + Self::from_recovered_tx(signed_tx.tx().tx(), caller) |
| 1357 | + } |
| 1358 | + TypedTransaction::EIP7702(signed_tx) => Self::from_recovered_tx(signed_tx.tx(), caller), |
| 1359 | + TypedTransaction::Deposit(tx) => Self::from_recovered_tx(tx, caller), |
| 1360 | + } |
| 1361 | + } |
| 1362 | +} |
| 1363 | + |
| 1364 | +impl FromRecoveredTx<TypedTransaction> for OpTransaction<TxEnv> { |
| 1365 | + fn from_recovered_tx(tx: &TypedTransaction, caller: Address) -> Self { |
| 1366 | + let base = TxEnv::from_recovered_tx(tx, caller); |
| 1367 | + |
| 1368 | + let deposit = if let TypedTransaction::Deposit(deposit_tx) = tx { |
| 1369 | + DepositTransactionParts { |
| 1370 | + source_hash: deposit_tx.source_hash, |
| 1371 | + mint: Some(deposit_tx.mint), |
| 1372 | + is_system_transaction: deposit_tx.is_system_transaction, |
| 1373 | + } |
| 1374 | + } else { |
| 1375 | + Default::default() |
| 1376 | + }; |
| 1377 | + |
| 1378 | + Self { base, deposit, enveloped_tx: None } |
| 1379 | + } |
| 1380 | +} |
| 1381 | + |
1542 | 1382 | #[cfg(test)] |
1543 | 1383 | mod tests { |
1544 | 1384 | use super::*; |
@@ -1785,4 +1625,38 @@ mod tests { |
1785 | 1625 |
|
1786 | 1626 | let _typed_tx: TypedTransaction = serde_json::from_str(tx).unwrap(); |
1787 | 1627 | } |
| 1628 | + |
| 1629 | + #[test] |
| 1630 | + fn test_from_recovered_tx_legacy() { |
| 1631 | + let tx = r#" |
| 1632 | + { |
| 1633 | + "Legacy": { |
| 1634 | + "chainId": "0x1", |
| 1635 | + "nonce": "0x0", |
| 1636 | + "gas": "0x5208", |
| 1637 | + "gasPrice": "0x1", |
| 1638 | + "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", |
| 1639 | + "value": "0x1", |
| 1640 | + "input": "0x", |
| 1641 | + "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0", |
| 1642 | + "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd", |
| 1643 | + "v": "0x1b", |
| 1644 | + "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515" |
| 1645 | + } |
| 1646 | + }"#; |
| 1647 | + |
| 1648 | + let typed_tx: TypedTransaction = serde_json::from_str(tx).unwrap(); |
| 1649 | + let sender = typed_tx.recover().unwrap(); |
| 1650 | + |
| 1651 | + // Test TxEnv conversion via FromRecoveredTx trait |
| 1652 | + let tx_env = TxEnv::from_recovered_tx(&typed_tx, sender); |
| 1653 | + assert_eq!(tx_env.caller, sender); |
| 1654 | + assert_eq!(tx_env.gas_limit, 0x5208); |
| 1655 | + assert_eq!(tx_env.gas_price, 1); |
| 1656 | + |
| 1657 | + // Test OpTransaction<TxEnv> conversion via FromRecoveredTx trait |
| 1658 | + let op_tx = OpTransaction::<TxEnv>::from_recovered_tx(&typed_tx, sender); |
| 1659 | + assert_eq!(op_tx.base.caller, sender); |
| 1660 | + assert_eq!(op_tx.base.gas_limit, 0x5208); |
| 1661 | + } |
1788 | 1662 | } |
0 commit comments