1use std::fmt::Debug;
2
3use alloy_consensus::Typed2718;
4pub use alloy_evm::EvmEnv;
5use alloy_evm::FromRecoveredTx;
6use alloy_network::{AnyRpcTransaction, AnyTxEnvelope, TransactionResponse};
7use alloy_primitives::{Address, B256, Bytes, U256};
8use op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, TxDeposit};
9use op_revm::{
10 OpTransaction,
11 transaction::{
12 OpTxTr,
13 deposit::{DEPOSIT_TRANSACTION_TYPE, DepositTransactionParts},
14 },
15};
16use revm::{
17 Context, Database, Journal,
18 context::{Block, BlockEnv, Cfg, CfgEnv, Transaction, TxEnv},
19 context_interface::{
20 ContextTr,
21 either::Either,
22 transaction::{AccessList, RecoveredAuthorization, SignedAuthorization},
23 },
24 inspector::JournalExt,
25 primitives::{TxKind, hardfork::SpecId},
26};
27use tempo_revm::{TempoBlockEnv, TempoTxEnv};
28
29use crate::backend::JournaledState;
30
31pub trait FoundryBlock: Block {
33 fn set_number(&mut self, number: U256);
35
36 fn set_beneficiary(&mut self, beneficiary: Address);
38
39 fn set_timestamp(&mut self, timestamp: U256);
41
42 fn set_gas_limit(&mut self, gas_limit: u64);
44
45 fn set_basefee(&mut self, basefee: u64);
47
48 fn set_difficulty(&mut self, difficulty: U256);
50
51 fn set_prevrandao(&mut self, prevrandao: Option<B256>);
53
54 fn set_blob_excess_gas_and_price(
56 &mut self,
57 _excess_blob_gas: u64,
58 _base_fee_update_fraction: u64,
59 );
60
61 fn timestamp_millis_part(&self) -> u64 {
65 0
66 }
67
68 fn set_timestamp_millis_part(&mut self, _millis: u64) {}
70}
71
72impl FoundryBlock for BlockEnv {
73 fn set_number(&mut self, number: U256) {
74 self.number = number;
75 }
76
77 fn set_beneficiary(&mut self, beneficiary: Address) {
78 self.beneficiary = beneficiary;
79 }
80
81 fn set_timestamp(&mut self, timestamp: U256) {
82 self.timestamp = timestamp;
83 }
84
85 fn set_gas_limit(&mut self, gas_limit: u64) {
86 self.gas_limit = gas_limit;
87 }
88
89 fn set_basefee(&mut self, basefee: u64) {
90 self.basefee = basefee;
91 }
92
93 fn set_difficulty(&mut self, difficulty: U256) {
94 self.difficulty = difficulty;
95 }
96
97 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
98 self.prevrandao = prevrandao;
99 }
100
101 fn set_blob_excess_gas_and_price(
102 &mut self,
103 excess_blob_gas: u64,
104 base_fee_update_fraction: u64,
105 ) {
106 self.set_blob_excess_gas_and_price(excess_blob_gas, base_fee_update_fraction);
107 }
108}
109
110impl FoundryBlock for TempoBlockEnv {
111 fn set_number(&mut self, number: U256) {
112 self.inner.set_number(number);
113 }
114
115 fn set_beneficiary(&mut self, beneficiary: Address) {
116 self.inner.set_beneficiary(beneficiary);
117 }
118
119 fn set_timestamp(&mut self, timestamp: U256) {
120 self.inner.set_timestamp(timestamp);
121 }
122
123 fn set_gas_limit(&mut self, gas_limit: u64) {
124 self.inner.set_gas_limit(gas_limit);
125 }
126
127 fn set_basefee(&mut self, basefee: u64) {
128 self.inner.set_basefee(basefee);
129 }
130
131 fn set_difficulty(&mut self, difficulty: U256) {
132 self.inner.set_difficulty(difficulty);
133 }
134
135 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
136 self.inner.set_prevrandao(prevrandao);
137 }
138
139 fn set_blob_excess_gas_and_price(
140 &mut self,
141 _excess_blob_gas: u64,
142 _base_fee_update_fraction: u64,
143 ) {
144 }
145
146 fn timestamp_millis_part(&self) -> u64 {
147 self.timestamp_millis_part
148 }
149
150 fn set_timestamp_millis_part(&mut self, millis: u64) {
151 self.timestamp_millis_part = millis;
152 }
153}
154
155pub trait FoundryTransaction: Transaction {
158 fn set_tx_type(&mut self, tx_type: u8);
160
161 fn set_caller(&mut self, caller: Address);
163
164 fn set_gas_limit(&mut self, gas_limit: u64);
166
167 fn set_gas_price(&mut self, gas_price: u128);
169
170 fn set_kind(&mut self, kind: TxKind);
172
173 fn set_value(&mut self, value: U256);
175
176 fn set_data(&mut self, data: Bytes);
178
179 fn set_nonce(&mut self, nonce: u64);
181
182 fn set_chain_id(&mut self, chain_id: Option<u64>);
184
185 fn set_access_list(&mut self, access_list: AccessList);
187
188 fn authorization_list_mut(
190 &mut self,
191 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>>;
192
193 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);
195
196 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);
198
199 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);
201
202 fn set_signed_authorization(&mut self, auth: Vec<SignedAuthorization>) {
204 *self.authorization_list_mut() = auth.into_iter().map(Either::Left).collect();
205 }
206
207 fn enveloped_tx(&self) -> Option<&Bytes> {
211 None
212 }
213
214 fn set_enveloped_tx(&mut self, _bytes: Bytes) {}
216
217 fn source_hash(&self) -> Option<B256> {
219 None
220 }
221
222 fn set_source_hash(&mut self, _source_hash: B256) {}
224
225 fn mint(&self) -> Option<u128> {
227 None
228 }
229
230 fn set_mint(&mut self, _mint: u128) {}
232
233 fn is_system_transaction(&self) -> bool {
235 false
236 }
237
238 fn set_system_transaction(&mut self, _is_system_transaction: bool) {}
240
241 fn is_deposit(&self) -> bool {
243 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
244 }
245
246 fn fee_token(&self) -> Option<Address> {
250 None
251 }
252
253 fn set_fee_token(&mut self, _token: Option<Address>) {}
255
256 fn fee_payer(&self) -> Option<Option<Address>> {
258 None
259 }
260
261 fn set_fee_payer(&mut self, _payer: Option<Option<Address>>) {}
263}
264
265impl FoundryTransaction for TxEnv {
266 fn set_tx_type(&mut self, tx_type: u8) {
267 self.tx_type = tx_type;
268 }
269
270 fn set_caller(&mut self, caller: Address) {
271 self.caller = caller;
272 }
273
274 fn set_gas_limit(&mut self, gas_limit: u64) {
275 self.gas_limit = gas_limit;
276 }
277
278 fn set_gas_price(&mut self, gas_price: u128) {
279 self.gas_price = gas_price;
280 }
281
282 fn set_kind(&mut self, kind: TxKind) {
283 self.kind = kind;
284 }
285
286 fn set_value(&mut self, value: U256) {
287 self.value = value;
288 }
289
290 fn set_data(&mut self, data: Bytes) {
291 self.data = data;
292 }
293
294 fn set_nonce(&mut self, nonce: u64) {
295 self.nonce = nonce;
296 }
297
298 fn set_chain_id(&mut self, chain_id: Option<u64>) {
299 self.chain_id = chain_id;
300 }
301
302 fn set_access_list(&mut self, access_list: AccessList) {
303 self.access_list = access_list;
304 }
305
306 fn authorization_list_mut(
307 &mut self,
308 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
309 &mut self.authorization_list
310 }
311
312 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
313 self.gas_priority_fee = gas_priority_fee;
314 }
315
316 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
317 self.blob_hashes = blob_hashes;
318 }
319
320 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
321 self.max_fee_per_blob_gas = max_fee_per_blob_gas;
322 }
323}
324
325impl<TX: FoundryTransaction> FoundryTransaction for OpTransaction<TX> {
326 fn set_tx_type(&mut self, tx_type: u8) {
327 self.base.set_tx_type(tx_type);
328 }
329
330 fn set_caller(&mut self, caller: Address) {
331 self.base.set_caller(caller);
332 }
333
334 fn set_gas_limit(&mut self, gas_limit: u64) {
335 self.base.set_gas_limit(gas_limit);
336 }
337
338 fn set_gas_price(&mut self, gas_price: u128) {
339 self.base.set_gas_price(gas_price);
340 }
341
342 fn set_kind(&mut self, kind: TxKind) {
343 self.base.set_kind(kind);
344 }
345
346 fn set_value(&mut self, value: U256) {
347 self.base.set_value(value);
348 }
349
350 fn set_data(&mut self, data: Bytes) {
351 self.base.set_data(data);
352 }
353
354 fn set_nonce(&mut self, nonce: u64) {
355 self.base.set_nonce(nonce);
356 }
357
358 fn set_chain_id(&mut self, chain_id: Option<u64>) {
359 self.base.set_chain_id(chain_id);
360 }
361
362 fn set_access_list(&mut self, access_list: AccessList) {
363 self.base.set_access_list(access_list);
364 }
365
366 fn authorization_list_mut(
367 &mut self,
368 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
369 self.base.authorization_list_mut()
370 }
371
372 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
373 self.base.set_gas_priority_fee(gas_priority_fee);
374 }
375
376 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
377
378 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
379
380 fn enveloped_tx(&self) -> Option<&Bytes> {
381 OpTxTr::enveloped_tx(self)
382 }
383
384 fn set_enveloped_tx(&mut self, bytes: Bytes) {
385 self.enveloped_tx = Some(bytes);
386 }
387
388 fn source_hash(&self) -> Option<B256> {
389 OpTxTr::source_hash(self)
390 }
391
392 fn set_source_hash(&mut self, source_hash: B256) {
393 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
394 self.deposit.source_hash = source_hash;
395 }
396 }
397
398 fn mint(&self) -> Option<u128> {
399 OpTxTr::mint(self)
400 }
401
402 fn set_mint(&mut self, mint: u128) {
403 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
404 self.deposit.mint = Some(mint);
405 }
406 }
407
408 fn is_system_transaction(&self) -> bool {
409 OpTxTr::is_system_transaction(self)
410 }
411
412 fn set_system_transaction(&mut self, is_system_transaction: bool) {
413 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
414 self.deposit.is_system_transaction = is_system_transaction;
415 }
416 }
417}
418
419impl FoundryTransaction for TempoTxEnv {
420 fn set_tx_type(&mut self, tx_type: u8) {
421 self.inner.set_tx_type(tx_type);
422 }
423
424 fn set_caller(&mut self, caller: Address) {
425 self.inner.set_caller(caller);
426 }
427
428 fn set_gas_limit(&mut self, gas_limit: u64) {
429 self.inner.set_gas_limit(gas_limit);
430 }
431
432 fn set_gas_price(&mut self, gas_price: u128) {
433 self.inner.set_gas_price(gas_price);
434 }
435
436 fn set_kind(&mut self, kind: TxKind) {
437 self.inner.set_kind(kind);
438 }
439
440 fn set_value(&mut self, value: U256) {
441 self.inner.set_value(value);
442 }
443
444 fn set_data(&mut self, data: Bytes) {
445 self.inner.set_data(data);
446 }
447
448 fn set_nonce(&mut self, nonce: u64) {
449 self.inner.set_nonce(nonce);
450 }
451
452 fn set_chain_id(&mut self, chain_id: Option<u64>) {
453 self.inner.set_chain_id(chain_id);
454 }
455
456 fn set_access_list(&mut self, access_list: AccessList) {
457 self.inner.set_access_list(access_list);
458 }
459
460 fn authorization_list_mut(
461 &mut self,
462 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
463 self.inner.authorization_list_mut()
464 }
465
466 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
467 self.inner.set_gas_priority_fee(gas_priority_fee);
468 }
469
470 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
471
472 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
473
474 fn fee_token(&self) -> Option<Address> {
475 self.fee_token
476 }
477
478 fn set_fee_token(&mut self, token: Option<Address>) {
479 self.fee_token = token;
480 }
481
482 fn fee_payer(&self) -> Option<Option<Address>> {
483 self.fee_payer
484 }
485
486 fn set_fee_payer(&mut self, payer: Option<Option<Address>>) {
487 self.fee_payer = payer;
488 }
489}
490
491pub trait FoundryContextExt:
496 ContextTr<
497 Block: FoundryBlock + Clone,
498 Tx: FoundryTransaction + Clone,
499 Cfg = CfgEnv<Self::Spec>,
500 Journal: JournalExt,
501 >
502{
503 type Spec: Into<SpecId> + Copy + Debug;
507
508 fn block_mut(&mut self) -> &mut Self::Block;
510
511 fn tx_mut(&mut self) -> &mut Self::Tx;
513
514 fn cfg_mut(&mut self) -> &mut Self::Cfg;
516
517 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState);
519
520 fn set_block(&mut self, block: Self::Block) {
522 *self.block_mut() = block;
523 }
524
525 fn set_tx(&mut self, tx: Self::Tx) {
527 *self.tx_mut() = tx;
528 }
529
530 fn set_cfg(&mut self, cfg: Self::Cfg) {
532 *self.cfg_mut() = cfg;
533 }
534
535 fn set_journal_inner(&mut self, journal_inner: JournaledState) {
537 *self.db_journal_inner_mut().1 = journal_inner;
538 }
539
540 fn set_evm(&mut self, evm_env: EvmEnv<Self::Spec, Self::Block>) {
542 *self.cfg_mut() = evm_env.cfg_env;
543 *self.block_mut() = evm_env.block_env;
544 }
545
546 fn tx_clone(&self) -> Self::Tx {
548 self.tx().clone()
549 }
550
551 fn evm_clone(&self) -> EvmEnv<Self::Spec, Self::Block> {
553 EvmEnv::new(self.cfg().clone(), self.block().clone())
554 }
555}
556
557impl<
558 BLOCK: FoundryBlock + Clone,
559 TX: FoundryTransaction + Clone,
560 SPEC: Into<SpecId> + Copy + Debug,
561 DB: Database,
562 C,
563> FoundryContextExt for Context<BLOCK, TX, CfgEnv<SPEC>, DB, Journal<DB>, C>
564{
565 type Spec = <Self::Cfg as Cfg>::Spec;
566
567 fn block_mut(&mut self) -> &mut Self::Block {
568 &mut self.block
569 }
570
571 fn tx_mut(&mut self) -> &mut Self::Tx {
572 &mut self.tx
573 }
574
575 fn cfg_mut(&mut self) -> &mut Self::Cfg {
576 &mut self.cfg
577 }
578
579 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
580 (&mut self.journaled_state.database, &mut self.journaled_state.inner)
581 }
582}
583
584pub trait FromAnyRpcTransaction: Sized {
590 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self>;
592}
593
594impl FromAnyRpcTransaction for TxEnv {
595 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
596 if let Some(envelope) = tx.as_envelope() {
597 Ok(Self::from_recovered_tx(envelope, tx.from()))
598 } else {
599 eyre::bail!("cannot convert unknown transaction type to TxEnv")
600 }
601 }
602}
603
604impl FromAnyRpcTransaction for OpTransaction<TxEnv> {
605 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
606 if let Some(envelope) = tx.as_envelope() {
607 return Ok(Self {
608 base: TxEnv::from_recovered_tx(envelope, tx.from()),
609 enveloped_tx: None,
610 deposit: Default::default(),
611 });
612 }
613
614 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
616 && unknown.ty() == DEPOSIT_TX_TYPE_ID
617 {
618 let mut fields = unknown.inner.fields.clone();
619 fields.insert("from".to_string(), serde_json::to_value(tx.from())?);
620 let deposit_tx: TxDeposit = fields
621 .deserialize_into()
622 .map_err(|e| eyre::eyre!("failed to deserialize deposit tx: {e}"))?;
623 let base = TxEnv::from_recovered_tx(&deposit_tx, tx.from());
624 let deposit = DepositTransactionParts {
625 source_hash: deposit_tx.source_hash,
626 mint: Some(deposit_tx.mint),
627 is_system_transaction: deposit_tx.is_system_transaction,
628 };
629 return Ok(Self { base, enveloped_tx: None, deposit });
630 }
631
632 eyre::bail!("cannot convert unknown transaction type to OpTransaction")
633 }
634}
635
636impl FromAnyRpcTransaction for TempoTxEnv {
637 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
638 use alloy_consensus::Transaction as _;
639 if let Some(envelope) = tx.as_envelope() {
640 return Ok(TxEnv::from_recovered_tx(envelope, tx.from()).into());
641 }
642
643 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
645 && unknown.ty() == tempo_alloy::primitives::TEMPO_TX_TYPE_ID
646 {
647 let base = TxEnv {
648 tx_type: unknown.ty(),
649 caller: tx.from(),
650 gas_limit: unknown.gas_limit(),
651 gas_price: unknown.max_fee_per_gas(),
652 gas_priority_fee: unknown.max_priority_fee_per_gas(),
653 kind: unknown.kind(),
654 value: unknown.value(),
655 data: unknown.input().clone(),
656 nonce: unknown.nonce(),
657 chain_id: unknown.chain_id(),
658 access_list: unknown.access_list().cloned().unwrap_or_default(),
659 ..Default::default()
660 };
661 let fee_token =
662 unknown.inner.fields.get_deserialized::<Address>("feeToken").and_then(Result::ok);
663 return Ok(Self { inner: base, fee_token, ..Default::default() });
664 }
665
666 eyre::bail!("cannot convert unknown transaction type to TempoTxEnv")
667 }
668}
669
670#[cfg(test)]
671mod tests {
672 use super::*;
673 use alloy_consensus::{Sealed, Signed, TxEip1559, transaction::Recovered};
674 use alloy_evm::{EthEvmFactory, EvmFactory};
675 use alloy_network::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
676 use alloy_op_evm::OpEvmFactory;
677 use alloy_primitives::Signature;
678 use alloy_rpc_types::{Transaction as RpcTransaction, TransactionInfo};
679 use alloy_serde::WithOtherFields;
680 use foundry_evm_hardforks::TempoHardfork;
681 use op_alloy_consensus::{OpTxEnvelope, transaction::OpTransactionInfo};
682 use op_alloy_rpc_types::Transaction as OpRpcTransaction;
683 use op_revm::OpSpecId;
684 use revm::database::EmptyDB;
685 use tempo_alloy::primitives::{
686 AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,
687 transaction::PrimitiveSignature,
688 };
689 use tempo_evm::TempoEvmFactory;
690
691 #[test]
692 fn eth_evm_foundry_context_ext_implementation() {
693 let mut evm = EthEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
694
695 evm.ctx_mut().block_mut().set_number(U256::from(123));
697 assert_eq!(evm.ctx().block().number(), U256::from(123));
698
699 evm.ctx_mut().tx_mut().set_nonce(99);
701 assert_eq!(evm.ctx().tx().nonce(), 99);
702
703 evm.ctx_mut().cfg_mut().spec = SpecId::AMSTERDAM;
705 assert_eq!(evm.ctx().cfg().spec, SpecId::AMSTERDAM);
706
707 let tx_env = evm.ctx().tx_clone();
709 evm.ctx_mut().set_tx(tx_env);
710 let evm_env = evm.ctx().evm_clone();
711 evm.ctx_mut().set_evm(evm_env);
712 }
713
714 #[test]
715 fn op_evm_foundry_context_ext_implementation() {
716 let mut evm = OpEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
717
718 evm.ctx_mut().block_mut().set_number(U256::from(123));
720 assert_eq!(evm.ctx().block().number(), U256::from(123));
721
722 evm.ctx_mut().tx_mut().set_nonce(99);
724 assert_eq!(evm.ctx().tx().nonce(), 99);
725
726 evm.ctx_mut().cfg_mut().spec = OpSpecId::JOVIAN;
728 assert_eq!(evm.ctx().cfg().spec, OpSpecId::JOVIAN);
729
730 let tx_env = evm.ctx().tx_clone();
732 evm.ctx_mut().set_tx(tx_env);
733 let evm_env = evm.ctx().evm_clone();
734 evm.ctx_mut().set_evm(evm_env);
735 }
736
737 #[test]
738 fn tempo_evm_foundry_context_ext_implementation() {
739 let mut evm = TempoEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
740
741 evm.ctx_mut().block_mut().set_number(U256::from(123));
743 assert_eq!(evm.ctx().block().number(), U256::from(123));
744
745 evm.ctx_mut().tx_mut().set_nonce(99);
747 assert_eq!(evm.ctx().tx().nonce(), 99);
748
749 evm.ctx_mut().cfg_mut().spec = TempoHardfork::Genesis;
751 assert_eq!(evm.ctx().cfg().spec, TempoHardfork::Genesis);
752
753 let tx_env = evm.ctx().tx_clone();
755 evm.ctx_mut().set_tx(tx_env);
756 let evm_env = evm.ctx().evm_clone();
757 evm.ctx_mut().set_evm(evm_env);
758 }
759
760 fn make_signed_eip1559() -> Signed<TxEip1559> {
761 Signed::new_unchecked(
762 TxEip1559 {
763 chain_id: 1,
764 nonce: 42,
765 gas_limit: 21001,
766 to: TxKind::Call(Address::with_last_byte(0xBB)),
767 value: U256::from(101),
768 ..Default::default()
769 },
770 Signature::new(U256::ZERO, U256::ZERO, false),
771 B256::ZERO,
772 )
773 }
774
775 #[test]
776 fn from_any_rpc_transaction_for_eth() {
777 let from = Address::random();
778 let signed_tx = make_signed_eip1559();
779 let rpc_tx = RpcTransaction::from_transaction(
780 Recovered::new_unchecked(signed_tx.into(), from),
781 TransactionInfo::default(),
782 );
783
784 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
785 let tx_env = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
786
787 assert_eq!(tx_env.caller, from);
788 assert_eq!(tx_env.nonce, 42);
789 assert_eq!(tx_env.gas_limit, 21001);
790 assert_eq!(tx_env.value, U256::from(101));
791 assert_eq!(tx_env.kind, TxKind::Call(Address::with_last_byte(0xBB)));
792 }
793
794 #[test]
795 fn from_any_rpc_transaction_for_op() {
796 let from = Address::random();
797 let signed_tx = make_signed_eip1559();
798
799 let rpc_tx = RpcTransaction::from_transaction(
801 Recovered::new_unchecked(signed_tx.into(), from),
802 TransactionInfo::default(),
803 );
804 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
805 let expected_base = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
806
807 let op_tx_env = OpTransaction::<TxEnv>::from_any_rpc_transaction(&any_tx).unwrap();
808 assert_eq!(op_tx_env.base, expected_base);
809 }
810
811 #[test]
812 fn from_any_rpc_transaction_unknown_envelope_errors() {
813 let unknown = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
814 hash: B256::ZERO,
815 inner: UnknownTypedTransaction {
816 ty: AnyTxType(0xFF),
817 fields: Default::default(),
818 memo: Default::default(),
819 },
820 });
821 let from = Address::random();
822 let any_tx = AnyRpcTransaction::new(WithOtherFields::new(RpcTransaction {
823 inner: Recovered::new_unchecked(unknown, from),
824 block_hash: None,
825 block_number: None,
826 transaction_index: None,
827 effective_gas_price: None,
828 block_timestamp: None,
829 }));
830
831 let result = TxEnv::from_any_rpc_transaction(&any_tx).unwrap_err();
832 assert!(result.to_string().contains("unknown transaction type"));
833 }
834
835 #[test]
836 fn from_any_rpc_transaction_for_op_deposit() {
837 let from = Address::random();
838 let source_hash = B256::random();
839 let deposit = TxDeposit {
840 source_hash,
841 from,
842 to: TxKind::Call(Address::with_last_byte(0xCC)),
843 mint: 1111,
844 value: U256::from(200),
845 gas_limit: 21000,
846 is_system_transaction: true,
847 input: Default::default(),
848 };
849
850 let op_rpc_tx = OpRpcTransaction::from_transaction(
852 Recovered::new_unchecked(OpTxEnvelope::Deposit(Sealed::new(deposit)), from),
853 OpTransactionInfo::default(),
854 );
855 let json = serde_json::to_value(&op_rpc_tx).unwrap();
856 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
857
858 let op_tx_env = OpTransaction::<TxEnv>::from_any_rpc_transaction(&any_tx).unwrap();
859 assert_eq!(op_tx_env.base.caller, from);
860 assert_eq!(op_tx_env.base.kind, TxKind::Call(Address::with_last_byte(0xCC)));
861 assert_eq!(op_tx_env.base.value, U256::from(200));
862 assert_eq!(op_tx_env.base.gas_limit, 21000);
863 assert_eq!(op_tx_env.deposit.source_hash, source_hash);
864 assert_eq!(op_tx_env.deposit.mint, Some(1111));
865 assert!(op_tx_env.deposit.is_system_transaction);
866 }
867
868 #[test]
869 fn from_any_rpc_transaction_for_tempo_eth_envelope() {
870 let from = Address::random();
871 let signed_tx = make_signed_eip1559();
872 let rpc_tx = RpcTransaction::from_transaction(
873 Recovered::new_unchecked(signed_tx.into(), from),
874 TransactionInfo::default(),
875 );
876 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
877
878 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
879 assert_eq!(tx_env.inner.caller, from);
880 assert_eq!(tx_env.inner.nonce, 42);
881 assert_eq!(tx_env.inner.gas_limit, 21001);
882 assert_eq!(tx_env.inner.value, U256::from(101));
883 assert_eq!(tx_env.fee_token, None);
884 }
885
886 #[test]
887 fn from_any_rpc_transaction_for_tempo_aa() {
888 let from = Address::random();
889 let fee_token = Some(Address::random());
890 let tempo_tx = TempoTransaction {
891 chain_id: 42431,
892 nonce: 42,
893 gas_limit: 424242,
894 fee_token,
895 nonce_key: U256::from(4242),
896 valid_after: Some(1800000000),
897 ..Default::default()
898 };
899 let aa_signed = AASigned::new_unhashed(
900 tempo_tx,
901 TempoSignature::Primitive(PrimitiveSignature::Secp256k1(Signature::new(
902 U256::ZERO,
903 U256::ZERO,
904 false,
905 ))),
906 );
907
908 let rpc_tx = RpcTransaction::from_transaction(
911 Recovered::new_unchecked(TempoTxEnvelope::AA(aa_signed), from),
912 TransactionInfo::default(),
913 );
914 let json = serde_json::to_value(&rpc_tx).unwrap();
915 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
916
917 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
918 assert_eq!(tx_env.inner.caller, from);
919 assert_eq!(tx_env.inner.nonce, 42);
920 assert_eq!(tx_env.inner.gas_limit, 424242);
921 assert_eq!(tx_env.inner.chain_id, Some(42431));
922 assert_eq!(tx_env.fee_token, fee_token);
923 }
924}