1use crate::backend::JournaledState;
2use alloy_chains::NamedChain;
3use alloy_consensus::{Transaction as _, Typed2718};
4use alloy_evm::FromRecoveredTx;
5use alloy_network::{AnyRpcTransaction, AnyTxEnvelope, TransactionResponse};
6use alloy_primitives::{Address, B256, Bytes, U256};
7use foundry_evm_networks::celo::CELO_DYNAMIC_FEE_TX_TYPE;
8use revm::{
9 Context, Database, Journal,
10 context::{Block, BlockEnv, Cfg, CfgEnv, Transaction, TxEnv},
11 context_interface::{
12 ContextTr,
13 either::Either,
14 transaction::{AccessList, RecoveredAuthorization, SignedAuthorization},
15 },
16 inspector::JournalExt,
17 primitives::{TxKind, hardfork::SpecId},
18};
19use std::fmt::Debug;
20use tempo_revm::{TempoBlockEnv, TempoTxEnv};
21
22#[cfg(feature = "optimism")]
23use op_revm::transaction::deposit::DEPOSIT_TRANSACTION_TYPE;
24
25pub use alloy_evm::EvmEnv;
26
27pub trait FoundryBlock: Block {
29 fn set_number(&mut self, number: U256);
31
32 fn set_slot_num(&mut self, slot_num: u64);
34
35 fn set_beneficiary(&mut self, beneficiary: Address);
37
38 fn set_timestamp(&mut self, timestamp: U256);
40
41 fn set_gas_limit(&mut self, gas_limit: u64);
43
44 fn set_basefee(&mut self, basefee: u64);
46
47 fn set_difficulty(&mut self, difficulty: U256);
49
50 fn set_prevrandao(&mut self, prevrandao: Option<B256>);
52
53 fn set_blob_excess_gas_and_price(
55 &mut self,
56 _excess_blob_gas: u64,
57 _base_fee_update_fraction: u64,
58 );
59
60 fn timestamp_millis_part(&self) -> u64 {
64 0
65 }
66
67 fn set_timestamp_millis_part(&mut self, _millis: u64) {}
69}
70
71impl FoundryBlock for BlockEnv {
72 fn set_number(&mut self, number: U256) {
73 self.number = number;
74 }
75
76 fn set_slot_num(&mut self, slot_num: u64) {
77 self.slot_num = slot_num;
78 }
79
80 fn set_beneficiary(&mut self, beneficiary: Address) {
81 self.beneficiary = beneficiary;
82 }
83
84 fn set_timestamp(&mut self, timestamp: U256) {
85 self.timestamp = timestamp;
86 }
87
88 fn set_gas_limit(&mut self, gas_limit: u64) {
89 self.gas_limit = gas_limit;
90 }
91
92 fn set_basefee(&mut self, basefee: u64) {
93 self.basefee = basefee;
94 }
95
96 fn set_difficulty(&mut self, difficulty: U256) {
97 self.difficulty = difficulty;
98 }
99
100 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
101 self.prevrandao = prevrandao;
102 }
103
104 fn set_blob_excess_gas_and_price(
105 &mut self,
106 excess_blob_gas: u64,
107 base_fee_update_fraction: u64,
108 ) {
109 self.set_blob_excess_gas_and_price(excess_blob_gas, base_fee_update_fraction);
110 }
111}
112
113impl FoundryBlock for TempoBlockEnv {
114 fn set_number(&mut self, number: U256) {
115 self.inner.set_number(number);
116 }
117
118 fn set_slot_num(&mut self, slot_num: u64) {
119 self.inner.set_slot_num(slot_num);
120 }
121
122 fn set_beneficiary(&mut self, beneficiary: Address) {
123 self.inner.set_beneficiary(beneficiary);
124 }
125
126 fn set_timestamp(&mut self, timestamp: U256) {
127 self.inner.set_timestamp(timestamp);
128 }
129
130 fn set_gas_limit(&mut self, gas_limit: u64) {
131 self.inner.set_gas_limit(gas_limit);
132 }
133
134 fn set_basefee(&mut self, basefee: u64) {
135 self.inner.set_basefee(basefee);
136 }
137
138 fn set_difficulty(&mut self, difficulty: U256) {
139 self.inner.set_difficulty(difficulty);
140 }
141
142 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
143 self.inner.set_prevrandao(prevrandao);
144 }
145
146 fn set_blob_excess_gas_and_price(
147 &mut self,
148 _excess_blob_gas: u64,
149 _base_fee_update_fraction: u64,
150 ) {
151 }
152
153 fn timestamp_millis_part(&self) -> u64 {
154 self.timestamp_millis_part
155 }
156
157 fn set_timestamp_millis_part(&mut self, millis: u64) {
158 self.timestamp_millis_part = millis;
159 }
160}
161
162pub trait FoundryTransaction: Transaction {
165 fn set_tx_type(&mut self, tx_type: u8);
167
168 fn set_caller(&mut self, caller: Address);
170
171 fn set_gas_limit(&mut self, gas_limit: u64);
173
174 fn set_gas_price(&mut self, gas_price: u128);
176
177 fn set_kind(&mut self, kind: TxKind);
179
180 fn set_value(&mut self, value: U256);
182
183 fn set_data(&mut self, data: Bytes);
185
186 fn set_nonce(&mut self, nonce: u64);
188
189 fn set_chain_id(&mut self, chain_id: Option<u64>);
191
192 fn set_access_list(&mut self, access_list: AccessList);
194
195 fn authorization_list_mut(
197 &mut self,
198 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>>;
199
200 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);
202
203 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);
205
206 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);
208
209 fn set_signed_authorization(&mut self, auth: Vec<SignedAuthorization>) {
211 *self.authorization_list_mut() = auth.into_iter().map(Either::Left).collect();
212 }
213
214 fn enveloped_tx(&self) -> Option<&Bytes> {
218 None
219 }
220
221 fn set_enveloped_tx(&mut self, _bytes: Bytes) {}
223
224 fn source_hash(&self) -> Option<B256> {
226 None
227 }
228
229 fn set_source_hash(&mut self, _source_hash: B256) {}
231
232 fn mint(&self) -> Option<u128> {
234 None
235 }
236
237 fn set_mint(&mut self, _mint: u128) {}
239
240 fn is_system_transaction(&self) -> bool {
242 false
243 }
244
245 fn set_system_transaction(&mut self, _is_system_transaction: bool) {}
247
248 fn is_deposit(&self) -> bool {
250 #[cfg(feature = "optimism")]
251 {
252 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
253 }
254 #[cfg(not(feature = "optimism"))]
255 {
256 false
257 }
258 }
259
260 fn fee_token(&self) -> Option<Address> {
264 None
265 }
266
267 fn set_fee_token(&mut self, _token: Option<Address>) {}
269
270 fn fee_payer(&self) -> Option<Option<Address>> {
272 None
273 }
274
275 fn set_fee_payer(&mut self, _payer: Option<Option<Address>>) {}
277}
278
279impl FoundryTransaction for TxEnv {
280 fn set_tx_type(&mut self, tx_type: u8) {
281 self.tx_type = tx_type;
282 }
283
284 fn set_caller(&mut self, caller: Address) {
285 self.caller = caller;
286 }
287
288 fn set_gas_limit(&mut self, gas_limit: u64) {
289 self.gas_limit = gas_limit;
290 }
291
292 fn set_gas_price(&mut self, gas_price: u128) {
293 self.gas_price = gas_price;
294 }
295
296 fn set_kind(&mut self, kind: TxKind) {
297 self.kind = kind;
298 }
299
300 fn set_value(&mut self, value: U256) {
301 self.value = value;
302 }
303
304 fn set_data(&mut self, data: Bytes) {
305 self.data = data;
306 }
307
308 fn set_nonce(&mut self, nonce: u64) {
309 self.nonce = nonce;
310 }
311
312 fn set_chain_id(&mut self, chain_id: Option<u64>) {
313 self.chain_id = chain_id;
314 }
315
316 fn set_access_list(&mut self, access_list: AccessList) {
317 self.access_list = access_list;
318 }
319
320 fn authorization_list_mut(
321 &mut self,
322 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
323 &mut self.authorization_list
324 }
325
326 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
327 self.gas_priority_fee = gas_priority_fee;
328 }
329
330 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
331 self.blob_hashes = blob_hashes;
332 }
333
334 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
335 self.max_fee_per_blob_gas = max_fee_per_blob_gas;
336 }
337}
338
339impl FoundryTransaction for TempoTxEnv {
340 fn set_tx_type(&mut self, tx_type: u8) {
341 self.inner.set_tx_type(tx_type);
342 }
343
344 fn set_caller(&mut self, caller: Address) {
345 self.inner.set_caller(caller);
346 }
347
348 fn set_gas_limit(&mut self, gas_limit: u64) {
349 self.inner.set_gas_limit(gas_limit);
350 }
351
352 fn set_gas_price(&mut self, gas_price: u128) {
353 self.inner.set_gas_price(gas_price);
354 }
355
356 fn set_kind(&mut self, kind: TxKind) {
357 self.inner.set_kind(kind);
358 if let Some(call) =
359 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
360 {
361 call.to = kind;
362 }
363 }
364
365 fn set_value(&mut self, value: U256) {
366 self.inner.set_value(value);
367 if let Some(call) =
368 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
369 {
370 call.value = value;
371 }
372 }
373
374 fn set_data(&mut self, data: Bytes) {
375 self.inner.set_data(data.clone());
376 if let Some(call) =
377 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
378 {
379 call.input = data;
380 }
381 }
382
383 fn set_nonce(&mut self, nonce: u64) {
384 self.inner.set_nonce(nonce);
385 }
386
387 fn set_chain_id(&mut self, chain_id: Option<u64>) {
388 self.inner.set_chain_id(chain_id);
389 }
390
391 fn set_access_list(&mut self, access_list: AccessList) {
392 self.inner.set_access_list(access_list);
393 }
394
395 fn authorization_list_mut(
396 &mut self,
397 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
398 self.inner.authorization_list_mut()
399 }
400
401 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
402 self.inner.set_gas_priority_fee(gas_priority_fee);
403 }
404
405 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
406
407 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
408
409 fn fee_token(&self) -> Option<Address> {
410 self.fee_token
411 }
412
413 fn set_fee_token(&mut self, token: Option<Address>) {
414 self.fee_token = token;
415 }
416
417 fn fee_payer(&self) -> Option<Option<Address>> {
418 self.fee_payer
419 }
420
421 fn set_fee_payer(&mut self, payer: Option<Option<Address>>) {
422 self.fee_payer = payer;
423 }
424}
425
426pub trait FoundryChain<Tx>: Clone + Debug + Default + Send + Sync {
430 fn for_transaction(_tx: &Tx) -> Self {
432 Self::default()
433 }
434
435 fn for_block(
437 _grandparent: &[Tx],
438 _parent: &[Tx],
439 _current: &[Tx],
440 _current_tx_index: usize,
441 ) -> Self {
442 Self::default()
443 }
444
445 fn refresh_journal<J: FoundryJournal>(&self, _journal: &mut J) {}
447}
448
449impl<Tx> FoundryChain<Tx> for () {}
450
451pub trait FoundryCfg:
453 Cfg<Spec: Into<SpecId> + Copy + Debug> + Clone + From<CfgEnv<Self::Spec>> + Into<CfgEnv<Self::Spec>>
454{
455 fn cfg_env(&self) -> &CfgEnv<Self::Spec>;
457
458 fn cfg_env_mut(&mut self) -> &mut CfgEnv<Self::Spec>;
460
461 fn set_spec_and_gas_params(&mut self, spec: Self::Spec) {
463 self.cfg_env_mut().set_spec_and_mainnet_gas_params(spec);
464 }
465}
466
467impl<SPEC: Into<SpecId> + Copy + Debug> FoundryCfg for CfgEnv<SPEC> {
468 fn cfg_env(&self) -> &Self {
469 self
470 }
471
472 fn cfg_env_mut(&mut self) -> &mut Self {
473 self
474 }
475}
476
477#[cfg(feature = "monad")]
478impl FoundryCfg for monad_revm::MonadCfgEnv {
479 fn cfg_env(&self) -> &CfgEnv<Self::Spec> {
480 self.inner()
481 }
482
483 fn cfg_env_mut(&mut self) -> &mut CfgEnv<Self::Spec> {
484 self.inner_mut()
485 }
486
487 fn set_spec_and_gas_params(&mut self, spec: Self::Spec) {
488 self.inner_mut().spec = spec;
489 self.inner_mut().set_gas_params(monad_revm::instructions::monad_gas_params(spec));
490 }
491}
492
493pub trait FoundryJournal: JournalExt {
495 fn db_journal_inner_mut(&mut self) -> (&mut Self::Database, &mut JournaledState);
497
498 fn journal_inner(&self) -> &JournaledState;
500
501 #[cfg(feature = "monad")]
503 fn capture_reserve_balance(
504 &self,
505 ) -> monad_revm::reserve_balance::tracker::ReserveBalanceTracker {
506 monad_revm::reserve_balance::tracker::ReserveBalanceTracker::default()
507 }
508
509 #[cfg(feature = "monad")]
511 fn restore_reserve_balance(
512 &mut self,
513 _tracker: monad_revm::reserve_balance::tracker::ReserveBalanceTracker,
514 ) {
515 }
516
517 #[cfg(feature = "monad")]
521 fn preserves_reserve_balance(&self) -> bool {
522 false
523 }
524
525 #[cfg(feature = "monad")]
527 fn set_preserve_reserve_balance(&mut self, _preserve: bool) {}
528}
529
530impl<DB: Database> FoundryJournal for Journal<DB> {
531 fn db_journal_inner_mut(&mut self) -> (&mut DB, &mut JournaledState) {
532 (&mut self.database, &mut self.inner)
533 }
534
535 fn journal_inner(&self) -> &JournaledState {
536 &self.inner
537 }
538}
539
540#[cfg(feature = "monad")]
541impl<DB: Database> FoundryJournal for monad_revm::MonadJournal<DB> {
542 fn db_journal_inner_mut(&mut self) -> (&mut DB, &mut JournaledState) {
543 Journal::db_journal_inner_mut(self)
544 }
545
546 fn journal_inner(&self) -> &JournaledState {
547 Journal::journal_inner(self)
548 }
549
550 fn capture_reserve_balance(
551 &self,
552 ) -> monad_revm::reserve_balance::tracker::ReserveBalanceTracker {
553 monad_revm::MonadJournalTr::reserve_balance(self).clone()
554 }
555
556 fn restore_reserve_balance(
557 &mut self,
558 tracker: monad_revm::reserve_balance::tracker::ReserveBalanceTracker,
559 ) {
560 *monad_revm::MonadJournalTr::reserve_balance_mut(self) = tracker;
561 }
562
563 fn preserves_reserve_balance(&self) -> bool {
564 monad_revm::MonadJournalTr::preserves_reserve_balance_tracker(self)
565 }
566
567 fn set_preserve_reserve_balance(&mut self, preserve: bool) {
568 monad_revm::MonadJournalTr::set_preserve_reserve_balance_tracker(self, preserve);
569 }
570}
571
572pub trait FoundryContextExt:
577 ContextTr<
578 Block: FoundryBlock + Clone,
579 Tx: FoundryTransaction + Clone,
580 Cfg: FoundryCfg<Spec = Self::Spec>,
581 Journal: FoundryJournal,
582 Chain: FoundryChain<Self::Tx>,
583 >
584{
585 type Spec: Into<SpecId> + Copy + Debug;
589
590 fn block_mut(&mut self) -> &mut Self::Block;
592
593 fn tx_mut(&mut self) -> &mut Self::Tx;
595
596 fn cfg_mut(&mut self) -> &mut Self::Cfg;
598
599 fn cfg_env(&self) -> &CfgEnv<Self::Spec> {
601 self.cfg().cfg_env()
602 }
603
604 fn cfg_env_mut(&mut self) -> &mut CfgEnv<Self::Spec> {
606 self.cfg_mut().cfg_env_mut()
607 }
608
609 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
611 self.journal_mut().db_journal_inner_mut()
612 }
613
614 fn journal_inner(&self) -> &JournaledState {
616 self.journal().journal_inner()
617 }
618
619 fn set_spec_and_gas_params(&mut self, spec: Self::Spec) {
621 self.cfg_mut().set_spec_and_gas_params(spec);
622 }
623
624 fn set_block(&mut self, block: Self::Block) {
626 *self.block_mut() = block;
627 }
628
629 fn set_tx(&mut self, tx: Self::Tx) {
631 *self.tx_mut() = tx;
632 }
633
634 fn set_cfg(&mut self, cfg: Self::Cfg) {
636 *self.cfg_mut() = cfg;
637 }
638
639 fn set_journal_inner(&mut self, journal_inner: JournaledState) {
641 *self.db_journal_inner_mut().1 = journal_inner;
642 }
643
644 fn set_evm(&mut self, evm_env: EvmEnv<Self::Spec, Self::Block>) {
646 *self.cfg_mut() = evm_env.cfg_env.into();
647 *self.block_mut() = evm_env.block_env;
648 }
649
650 fn tx_clone(&self) -> Self::Tx {
652 self.tx().clone()
653 }
654
655 fn evm_clone(&self) -> EvmEnv<Self::Spec, Self::Block> {
657 EvmEnv::new(self.cfg().clone().into(), self.block().clone())
658 }
659}
660
661pub fn refresh_chain_journal<CTX: FoundryContextExt>(context: &mut CTX) {
663 let chain = context.chain().clone();
664 chain.refresh_journal(context.journal_mut());
665}
666
667impl<
668 BLOCK: FoundryBlock + Clone,
669 TX: FoundryTransaction + Clone,
670 CFG: FoundryCfg,
671 DB: Database,
672 J: FoundryJournal<Database = DB>,
673 C: FoundryChain<TX>,
674> FoundryContextExt for Context<BLOCK, TX, CFG, DB, J, C>
675{
676 type Spec = <Self::Cfg as Cfg>::Spec;
677
678 fn block_mut(&mut self) -> &mut Self::Block {
679 &mut self.block
680 }
681
682 fn tx_mut(&mut self) -> &mut Self::Tx {
683 &mut self.tx
684 }
685
686 fn cfg_mut(&mut self) -> &mut Self::Cfg {
687 &mut self.cfg
688 }
689}
690
691pub trait FromAnyRpcTransaction: Sized {
696 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self>;
698}
699
700impl FromAnyRpcTransaction for TxEnv {
701 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
702 if let Some(envelope) = tx.as_envelope() {
703 return Ok(Self::from_recovered_tx(envelope, tx.from()));
704 }
705
706 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
712 && unknown.ty() == CELO_DYNAMIC_FEE_TX_TYPE
713 && matches!(
714 unknown.chain_id().and_then(NamedChain::from_chain_id),
715 Some(NamedChain::Celo | NamedChain::CeloSepolia)
716 )
717 {
718 return Ok(Self {
719 tx_type: CELO_DYNAMIC_FEE_TX_TYPE,
720 caller: tx.from(),
721 gas_limit: unknown.gas_limit(),
722 gas_price: unknown.max_fee_per_gas(),
723 gas_priority_fee: unknown.max_priority_fee_per_gas(),
724 kind: unknown.kind(),
725 value: unknown.value(),
726 data: unknown.input().clone(),
727 nonce: unknown.nonce(),
728 chain_id: unknown.chain_id(),
729 access_list: unknown.access_list().cloned().unwrap_or_default(),
730 ..Default::default()
731 });
732 }
733
734 eyre::bail!("cannot convert unknown transaction type to TxEnv");
735 }
736}
737
738impl FromAnyRpcTransaction for TempoTxEnv {
739 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
740 if let Some(envelope) = tx.as_envelope() {
741 return Ok(TxEnv::from_recovered_tx(envelope, tx.from()).into());
742 }
743
744 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
746 && unknown.ty() == tempo_alloy::primitives::TEMPO_TX_TYPE_ID
747 {
748 let base = TxEnv {
749 tx_type: unknown.ty(),
750 caller: tx.from(),
751 gas_limit: unknown.gas_limit(),
752 gas_price: unknown.max_fee_per_gas(),
753 gas_priority_fee: unknown.max_priority_fee_per_gas(),
754 kind: unknown.kind(),
755 value: unknown.value(),
756 data: unknown.input().clone(),
757 nonce: unknown.nonce(),
758 chain_id: unknown.chain_id(),
759 access_list: unknown.access_list().cloned().unwrap_or_default(),
760 ..Default::default()
761 };
762 let fee_token =
763 unknown.inner.fields.get_deserialized::<Address>("feeToken").and_then(Result::ok);
764 return Ok(Self { inner: base, fee_token, ..Default::default() });
765 }
766
767 eyre::bail!("cannot convert unknown transaction type to TempoTxEnv");
768 }
769}
770
771#[cfg(feature = "base")]
772mod base {
773 use super::*;
774 use base_common_consensus::BaseTxEnvelope;
775 use base_common_evm::{
776 BaseTransaction, BaseTxTr, DEPOSIT_TRANSACTION_TYPE, EIP8130_TRANSACTION_TYPE,
777 };
778 use base_common_rpc_types::Transaction as BaseRpcTransaction;
779
780 impl<TX: FoundryTransaction> FoundryTransaction for BaseTransaction<TX> {
781 fn set_tx_type(&mut self, tx_type: u8) {
782 self.base.set_tx_type(tx_type);
783 }
784
785 fn set_caller(&mut self, caller: Address) {
786 self.base.set_caller(caller);
787 }
788
789 fn set_gas_limit(&mut self, gas_limit: u64) {
790 self.base.set_gas_limit(gas_limit);
791 }
792
793 fn set_gas_price(&mut self, gas_price: u128) {
794 self.base.set_gas_price(gas_price);
795 }
796
797 fn set_kind(&mut self, kind: TxKind) {
798 self.base.set_kind(kind);
799 }
800
801 fn set_value(&mut self, value: U256) {
802 self.base.set_value(value);
803 }
804
805 fn set_data(&mut self, data: Bytes) {
806 self.base.set_data(data);
807 }
808
809 fn set_nonce(&mut self, nonce: u64) {
810 self.base.set_nonce(nonce);
811 }
812
813 fn set_chain_id(&mut self, chain_id: Option<u64>) {
814 self.base.set_chain_id(chain_id);
815 }
816
817 fn set_access_list(&mut self, access_list: AccessList) {
818 self.base.set_access_list(access_list);
819 }
820
821 fn authorization_list_mut(
822 &mut self,
823 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
824 self.base.authorization_list_mut()
825 }
826
827 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
828 self.base.set_gas_priority_fee(gas_priority_fee);
829 }
830
831 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
832 self.base.set_blob_hashes(blob_hashes);
833 }
834
835 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
836 self.base.set_max_fee_per_blob_gas(max_fee_per_blob_gas);
837 }
838
839 fn enveloped_tx(&self) -> Option<&Bytes> {
840 BaseTxTr::enveloped_tx(self)
841 }
842
843 fn set_enveloped_tx(&mut self, bytes: Bytes) {
844 self.enveloped_tx = Some(bytes);
845 }
846
847 fn source_hash(&self) -> Option<B256> {
848 BaseTxTr::source_hash(self)
849 }
850
851 fn set_source_hash(&mut self, source_hash: B256) {
852 self.deposit.source_hash = source_hash;
853 }
854
855 fn mint(&self) -> Option<u128> {
856 BaseTxTr::mint(self)
857 }
858
859 fn set_mint(&mut self, mint: u128) {
860 self.deposit.mint = Some(mint);
861 }
862
863 fn is_system_transaction(&self) -> bool {
864 BaseTxTr::is_system_transaction(self)
865 }
866
867 fn set_system_transaction(&mut self, is_system_transaction: bool) {
868 self.deposit.is_system_transaction = is_system_transaction;
869 }
870
871 fn is_deposit(&self) -> bool {
872 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
873 }
874 }
875
876 impl FromAnyRpcTransaction for BaseTransaction<TxEnv> {
877 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
878 let envelope = match BaseTxEnvelope::try_from(tx.clone()) {
879 Ok(envelope) => envelope,
880 Err(_) if tx.ty() == EIP8130_TRANSACTION_TYPE => {
881 let rpc_tx =
882 serde_json::from_value::<BaseRpcTransaction>(serde_json::to_value(tx)?)
883 .map_err(|err| {
884 eyre::eyre!(
885 "cannot convert RPC transaction to Base envelope: {err}"
886 )
887 })?;
888 rpc_tx.inner.into_inner()
889 }
890 Err(_) => eyre::bail!("cannot convert transaction to BaseTxEnvelope"),
891 };
892 Ok(Self::from_recovered_tx(&envelope, tx.from()))
893 }
894 }
895}
896
897#[cfg(feature = "optimism")]
898mod optimism {
899 use super::*;
900 use alloy_eips::eip2718::Encodable2718;
901 use alloy_op_evm::OpTx;
902 use op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, TxDeposit};
903 use op_revm::{OpTransaction, transaction::OpTxTr};
904
905 impl<TX: FoundryTransaction> FoundryTransaction for OpTransaction<TX> {
906 fn set_tx_type(&mut self, tx_type: u8) {
907 self.base.set_tx_type(tx_type);
908 }
909
910 fn set_caller(&mut self, caller: Address) {
911 self.base.set_caller(caller);
912 }
913
914 fn set_gas_limit(&mut self, gas_limit: u64) {
915 self.base.set_gas_limit(gas_limit);
916 }
917
918 fn set_gas_price(&mut self, gas_price: u128) {
919 self.base.set_gas_price(gas_price);
920 }
921
922 fn set_kind(&mut self, kind: TxKind) {
923 self.base.set_kind(kind);
924 }
925
926 fn set_value(&mut self, value: U256) {
927 self.base.set_value(value);
928 }
929
930 fn set_data(&mut self, data: Bytes) {
931 self.base.set_data(data);
932 }
933
934 fn set_nonce(&mut self, nonce: u64) {
935 self.base.set_nonce(nonce);
936 }
937
938 fn set_chain_id(&mut self, chain_id: Option<u64>) {
939 self.base.set_chain_id(chain_id);
940 }
941
942 fn set_access_list(&mut self, access_list: AccessList) {
943 self.base.set_access_list(access_list);
944 }
945
946 fn authorization_list_mut(
947 &mut self,
948 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
949 self.base.authorization_list_mut()
950 }
951
952 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
953 self.base.set_gas_priority_fee(gas_priority_fee);
954 }
955
956 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
957
958 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
959
960 fn enveloped_tx(&self) -> Option<&Bytes> {
961 OpTxTr::enveloped_tx(self)
962 }
963
964 fn set_enveloped_tx(&mut self, bytes: Bytes) {
965 self.enveloped_tx = Some(bytes);
966 }
967
968 fn source_hash(&self) -> Option<B256> {
969 OpTxTr::source_hash(self)
970 }
971
972 fn set_source_hash(&mut self, source_hash: B256) {
973 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
974 self.deposit.source_hash = source_hash;
975 }
976 }
977
978 fn mint(&self) -> Option<u128> {
979 OpTxTr::mint(self)
980 }
981
982 fn set_mint(&mut self, mint: u128) {
983 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
984 self.deposit.mint = Some(mint);
985 }
986 }
987
988 fn is_system_transaction(&self) -> bool {
989 OpTxTr::is_system_transaction(self)
990 }
991
992 fn set_system_transaction(&mut self, is_system_transaction: bool) {
993 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
994 self.deposit.is_system_transaction = is_system_transaction;
995 }
996 }
997 }
998
999 impl FoundryTransaction for OpTx {
1000 fn set_tx_type(&mut self, tx_type: u8) {
1001 self.0.set_tx_type(tx_type);
1002 }
1003
1004 fn set_caller(&mut self, caller: Address) {
1005 self.0.set_caller(caller);
1006 }
1007
1008 fn set_gas_limit(&mut self, gas_limit: u64) {
1009 self.0.set_gas_limit(gas_limit);
1010 }
1011
1012 fn set_gas_price(&mut self, gas_price: u128) {
1013 self.0.set_gas_price(gas_price);
1014 }
1015
1016 fn set_kind(&mut self, kind: TxKind) {
1017 self.0.set_kind(kind);
1018 }
1019
1020 fn set_value(&mut self, value: U256) {
1021 self.0.set_value(value);
1022 }
1023
1024 fn set_data(&mut self, data: Bytes) {
1025 self.0.set_data(data);
1026 }
1027
1028 fn set_nonce(&mut self, nonce: u64) {
1029 self.0.set_nonce(nonce);
1030 }
1031
1032 fn set_chain_id(&mut self, chain_id: Option<u64>) {
1033 self.0.set_chain_id(chain_id);
1034 }
1035
1036 fn set_access_list(&mut self, access_list: AccessList) {
1037 self.0.set_access_list(access_list);
1038 }
1039
1040 fn authorization_list_mut(
1041 &mut self,
1042 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
1043 self.0.authorization_list_mut()
1044 }
1045
1046 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
1047 self.0.set_gas_priority_fee(gas_priority_fee);
1048 }
1049
1050 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
1051
1052 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
1053
1054 fn enveloped_tx(&self) -> Option<&Bytes> {
1055 FoundryTransaction::enveloped_tx(&self.0)
1056 }
1057
1058 fn set_enveloped_tx(&mut self, bytes: Bytes) {
1059 self.0.set_enveloped_tx(bytes);
1060 }
1061
1062 fn source_hash(&self) -> Option<B256> {
1063 FoundryTransaction::source_hash(&self.0)
1064 }
1065
1066 fn set_source_hash(&mut self, source_hash: B256) {
1067 self.0.set_source_hash(source_hash);
1068 }
1069
1070 fn mint(&self) -> Option<u128> {
1071 FoundryTransaction::mint(&self.0)
1072 }
1073
1074 fn set_mint(&mut self, mint: u128) {
1075 self.0.set_mint(mint);
1076 }
1077
1078 fn is_system_transaction(&self) -> bool {
1079 FoundryTransaction::is_system_transaction(&self.0)
1080 }
1081
1082 fn set_system_transaction(&mut self, is_system_transaction: bool) {
1083 self.0.set_system_transaction(is_system_transaction);
1084 }
1085 }
1086
1087 impl FromAnyRpcTransaction for OpTx {
1088 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
1089 if let Some(envelope) = tx.as_envelope() {
1090 return Ok(Self(OpTransaction::<TxEnv> {
1091 base: TxEnv::from_recovered_tx(envelope, tx.from()),
1092 enveloped_tx: Some(envelope.encoded_2718().into()),
1095 deposit: Default::default(),
1096 }));
1097 }
1098
1099 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
1101 && unknown.ty() == DEPOSIT_TX_TYPE_ID
1102 {
1103 let mut fields = unknown.inner.fields.clone();
1104 fields.insert("from".to_string(), serde_json::to_value(tx.from())?);
1105 let deposit_tx: TxDeposit = fields
1106 .deserialize_into()
1107 .map_err(|e| eyre::eyre!("failed to deserialize deposit tx: {e}"))?;
1108 return Ok(Self::from_recovered_tx(&deposit_tx, deposit_tx.from));
1109 }
1110
1111 eyre::bail!("cannot convert unknown transaction type to OpTransaction");
1112 }
1113 }
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118 use super::*;
1119 use alloy_consensus::{Signed, TxEip1559, transaction::Recovered};
1120 use alloy_evm::{EthEvmFactory, EvmFactory};
1121 use alloy_network::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
1122 use alloy_primitives::Signature;
1123 use alloy_rpc_types::{Transaction as RpcTransaction, TransactionInfo};
1124 use alloy_serde::WithOtherFields;
1125 use foundry_evm_hardforks::TempoHardfork;
1126 use revm::database::EmptyDB;
1127 use std::num::NonZeroU64;
1128 use tempo_alloy::primitives::{
1129 AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,
1130 transaction::{Call, PrimitiveSignature},
1131 };
1132 use tempo_evm::TempoEvmFactory;
1133
1134 #[cfg(feature = "base")]
1135 use base_common_evm::{BaseEvmFactory, BaseSpecId, BaseTransaction, BaseUpgrade};
1136
1137 #[test]
1138 fn eth_evm_foundry_context_ext_implementation() {
1139 let mut evm = EthEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
1140
1141 evm.ctx_mut().block_mut().set_number(U256::from(123));
1143 assert_eq!(evm.ctx().block().number(), U256::from(123));
1144
1145 evm.ctx_mut().tx_mut().set_nonce(99);
1147 assert_eq!(evm.ctx().tx().nonce(), 99);
1148
1149 evm.ctx_mut().cfg_mut().spec = SpecId::AMSTERDAM;
1151 assert_eq!(evm.ctx().cfg().spec, SpecId::AMSTERDAM);
1152
1153 let tx_env = evm.ctx().tx_clone();
1155 evm.ctx_mut().set_tx(tx_env);
1156 let evm_env = evm.ctx().evm_clone();
1157 evm.ctx_mut().set_evm(evm_env);
1158 }
1159
1160 #[cfg(feature = "base")]
1161 #[test]
1162 fn base_evm_foundry_context_ext_implementation() {
1163 let mut evm = BaseEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
1164
1165 evm.ctx_mut().block_mut().set_number(U256::from(123));
1166 assert_eq!(evm.ctx().block().number(), U256::from(123));
1167
1168 evm.ctx_mut().tx_mut().set_nonce(99);
1169 assert_eq!(evm.ctx().tx().nonce(), 99);
1170
1171 evm.ctx_mut().cfg_mut().spec = BaseSpecId::new(BaseUpgrade::Beryl);
1172 assert_eq!(evm.ctx().cfg().spec, BaseSpecId::new(BaseUpgrade::Beryl));
1173
1174 let tx_env = evm.ctx().tx_clone();
1175 evm.ctx_mut().set_tx(tx_env);
1176 let evm_env = evm.ctx().evm_clone();
1177 evm.ctx_mut().set_evm(evm_env);
1178 }
1179
1180 #[test]
1181 #[cfg(feature = "monad")]
1182 fn monad_evm_foundry_context_ext_implementation() {
1183 let mut evm = alloy_monad_evm::MonadEvmFactory::default().create_evm(
1184 EmptyDB::default(),
1185 EvmEnv::new(
1186 CfgEnv::new_with_spec(monad_revm::MonadHardfork::MonadNine),
1187 BlockEnv::default(),
1188 ),
1189 );
1190
1191 evm.ctx_mut().block_mut().set_number(U256::from(123));
1193 assert_eq!(evm.ctx().block().number(), U256::from(123));
1194
1195 evm.ctx_mut().tx_mut().set_nonce(99);
1197 assert_eq!(evm.ctx().tx().nonce(), 99);
1198
1199 evm.ctx_mut().cfg_mut().spec = monad_revm::MonadHardfork::MonadEight;
1201 assert_eq!(evm.ctx().cfg().spec, monad_revm::MonadHardfork::MonadEight);
1202
1203 let tx_env = evm.ctx().tx_clone();
1205 evm.ctx_mut().set_tx(tx_env);
1206 let evm_env = evm.ctx().evm_clone();
1207 evm.ctx_mut().set_evm(evm_env);
1208 evm.ctx_mut().journal_mut().set_preserve_reserve_balance(true);
1209 let mut inner = evm.ctx().journal_inner().clone();
1210 inner.depth = 2;
1211 evm.ctx_mut().set_journal_inner(inner);
1212 assert_eq!(evm.ctx().journal_inner().depth, 2);
1213 assert!(evm.ctx().journal().preserves_reserve_balance());
1214 }
1215
1216 #[test]
1217 #[cfg(feature = "monad")]
1218 fn monad_memory_limit_follows_hardfork_transitions() {
1219 const FOUNDRY_MEMORY_LIMIT: u64 = 128 * 1024 * 1024;
1220
1221 let mut cfg = CfgEnv::new_with_spec(monad_revm::MonadHardfork::MonadEight);
1222 cfg.memory_limit = FOUNDRY_MEMORY_LIMIT;
1223 let mut evm = alloy_monad_evm::MonadEvmFactory::default()
1224 .create_evm(EmptyDB::default(), EvmEnv::new(cfg, BlockEnv::default()));
1225
1226 assert_eq!(evm.ctx().cfg().memory_limit(), FOUNDRY_MEMORY_LIMIT);
1227
1228 evm.ctx_mut().set_spec_and_gas_params(monad_revm::MonadHardfork::MonadNine);
1229 assert_eq!(evm.ctx().cfg().inner().memory_limit, FOUNDRY_MEMORY_LIMIT);
1230 assert_eq!(evm.ctx().cfg().memory_limit(), monad_revm::cfg::MONAD_MEMORY_LIMIT);
1231 assert_eq!(
1232 evm.ctx().cfg().inner().gas_params,
1233 monad_revm::instructions::monad_gas_params(monad_revm::MonadHardfork::MonadNine)
1234 );
1235
1236 evm.ctx_mut().set_spec_and_gas_params(monad_revm::MonadHardfork::MonadEight);
1237 assert_eq!(evm.ctx().cfg().memory_limit(), FOUNDRY_MEMORY_LIMIT);
1238 assert_eq!(
1239 evm.ctx().cfg().inner().gas_params,
1240 monad_revm::instructions::monad_gas_params(monad_revm::MonadHardfork::MonadEight)
1241 );
1242 }
1243
1244 #[test]
1245 fn tempo_evm_foundry_context_ext_implementation() {
1246 let mut evm = TempoEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
1247
1248 evm.ctx_mut().block_mut().set_number(U256::from(123));
1250 assert_eq!(evm.ctx().block().number(), U256::from(123));
1251
1252 evm.ctx_mut().tx_mut().set_nonce(99);
1254 assert_eq!(evm.ctx().tx().nonce(), 99);
1255
1256 evm.ctx_mut().cfg_mut().spec = TempoHardfork::Genesis;
1258 assert_eq!(evm.ctx().cfg().spec, TempoHardfork::Genesis);
1259
1260 let tx_env = evm.ctx().tx_clone();
1262 evm.ctx_mut().set_tx(tx_env);
1263 let evm_env = evm.ctx().evm_clone();
1264 evm.ctx_mut().set_evm(evm_env);
1265 }
1266
1267 #[test]
1268 fn tempo_tx_env_setters_update_aa_call_payload() {
1269 let old_to = TxKind::Call(Address::with_last_byte(0xAA));
1270 let new_to = TxKind::Create;
1271 let new_value = U256::from(123);
1272 let new_input = Bytes::from_static(b"local bytecode");
1273
1274 let mut tx_env = TempoTxEnv {
1275 inner: TxEnv {
1276 kind: old_to,
1277 value: U256::from(1),
1278 data: Bytes::from_static(b"original bytecode"),
1279 ..Default::default()
1280 },
1281 tempo_tx_env: Some(Box::new(tempo_revm::TempoBatchCallEnv {
1282 aa_calls: vec![Call {
1283 to: old_to,
1284 value: U256::from(1),
1285 input: Bytes::from_static(b"original bytecode"),
1286 }],
1287 ..Default::default()
1288 })),
1289 ..Default::default()
1290 };
1291
1292 tx_env.set_kind(new_to);
1293 tx_env.set_value(new_value);
1294 tx_env.set_data(new_input.clone());
1295
1296 assert_eq!(tx_env.inner.kind, new_to);
1297 assert_eq!(tx_env.inner.value, new_value);
1298 assert_eq!(tx_env.inner.data, new_input);
1299
1300 let call = &tx_env.tempo_tx_env.as_ref().unwrap().aa_calls[0];
1301 assert_eq!(call.to, new_to);
1302 assert_eq!(call.value, new_value);
1303 assert_eq!(call.input, new_input);
1304 }
1305
1306 fn make_signed_eip1559() -> Signed<TxEip1559> {
1307 Signed::new_unchecked(
1308 TxEip1559 {
1309 chain_id: 1,
1310 nonce: 42,
1311 gas_limit: 21001,
1312 to: TxKind::Call(Address::with_last_byte(0xBB)),
1313 value: U256::from(101),
1314 ..Default::default()
1315 },
1316 Signature::new(U256::ZERO, U256::ZERO, false),
1317 B256::ZERO,
1318 )
1319 }
1320
1321 #[test]
1322 fn from_any_rpc_transaction_for_eth() {
1323 let from = Address::random();
1324 let signed_tx = make_signed_eip1559();
1325 let rpc_tx = RpcTransaction::from_transaction(
1326 Recovered::new_unchecked(signed_tx.into(), from),
1327 TransactionInfo::default(),
1328 );
1329
1330 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
1331 let tx_env = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1332
1333 assert_eq!(tx_env.caller, from);
1334 assert_eq!(tx_env.nonce, 42);
1335 assert_eq!(tx_env.gas_limit, 21001);
1336 assert_eq!(tx_env.value, U256::from(101));
1337 assert_eq!(tx_env.kind, TxKind::Call(Address::with_last_byte(0xBB)));
1338 }
1339
1340 #[cfg(feature = "base")]
1341 #[test]
1342 fn from_any_rpc_transaction_for_base_eth_envelope() {
1343 let from = Address::random();
1344 let signed_tx = make_signed_eip1559();
1345 let rpc_tx = RpcTransaction::from_transaction(
1346 Recovered::new_unchecked(signed_tx.into(), from),
1347 TransactionInfo::default(),
1348 );
1349 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
1350
1351 let tx_env = BaseTransaction::<TxEnv>::from_any_rpc_transaction(&any_tx).unwrap();
1352 assert_eq!(tx_env.base.caller, from);
1353 assert_eq!(tx_env.base.nonce, 42);
1354 assert_eq!(tx_env.base.gas_limit, 21001);
1355 assert_eq!(tx_env.base.value, U256::from(101));
1356 assert!(tx_env.enveloped_tx.is_some());
1357 }
1358
1359 #[test]
1360 fn from_any_rpc_transaction_unknown_envelope_errors() {
1361 let unknown = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
1362 hash: B256::ZERO,
1363 inner: UnknownTypedTransaction {
1364 ty: AnyTxType(0xFF),
1365 fields: Default::default(),
1366 memo: Default::default(),
1367 },
1368 });
1369 let from = Address::random();
1370 let any_tx = AnyRpcTransaction::new(WithOtherFields::new(RpcTransaction {
1371 inner: Recovered::new_unchecked(unknown, from),
1372 block_hash: None,
1373 block_number: None,
1374 transaction_index: None,
1375 effective_gas_price: None,
1376 block_timestamp: None,
1377 }));
1378
1379 let result = TxEnv::from_any_rpc_transaction(&any_tx).unwrap_err();
1380 assert!(result.to_string().contains("unknown transaction type"));
1381 }
1382
1383 #[test]
1384 fn from_any_rpc_transaction_for_celo_dynamic_fee() {
1385 let from = Address::with_last_byte(0xAA);
1386 let to = Address::with_last_byte(0xBB);
1387 let fee_currency = Address::with_last_byte(0xCC);
1388 let json = serde_json::json!({
1389 "accessList": [],
1390 "blockHash": B256::ZERO,
1391 "blockNumber": "0x1",
1392 "chainId": "0xa4ec",
1393 "feeCurrency": fee_currency,
1394 "from": from,
1395 "gas": "0x5208",
1396 "gasPrice": "0x3",
1397 "hash": B256::ZERO,
1398 "input": "0x1234",
1399 "maxFeePerGas": "0x3",
1400 "maxPriorityFeePerGas": "0x1",
1401 "nonce": "0x2a",
1402 "r": B256::ZERO,
1403 "s": B256::ZERO,
1404 "to": to,
1405 "transactionIndex": "0x0",
1406 "type": "0x7b",
1407 "v": "0x0",
1408 "value": "0x65",
1409 "yParity": "0x0"
1410 });
1411 let mut non_celo_json = json.clone();
1412 non_celo_json["chainId"] = serde_json::json!("0x1");
1413 let non_celo_tx: AnyRpcTransaction = serde_json::from_value(non_celo_json).unwrap();
1414 assert!(TxEnv::from_any_rpc_transaction(&non_celo_tx).is_err());
1415
1416 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
1417
1418 let tx_env = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1419
1420 assert_eq!(tx_env.tx_type, CELO_DYNAMIC_FEE_TX_TYPE);
1421 assert_eq!(tx_env.caller, from);
1422 assert_eq!(tx_env.nonce, 42);
1423 assert_eq!(tx_env.gas_limit, 21000);
1424 assert_eq!(tx_env.gas_price, 3);
1425 assert_eq!(tx_env.gas_priority_fee, Some(1));
1426 assert_eq!(tx_env.kind, TxKind::Call(to));
1427 assert_eq!(tx_env.value, U256::from(101));
1428 assert_eq!(tx_env.data, Bytes::from_static(&[0x12, 0x34]));
1429 assert_eq!(tx_env.chain_id, Some(42_220));
1430 }
1431
1432 #[test]
1433 fn from_any_rpc_transaction_for_tempo_eth_envelope() {
1434 let from = Address::random();
1435 let signed_tx = make_signed_eip1559();
1436 let rpc_tx = RpcTransaction::from_transaction(
1437 Recovered::new_unchecked(signed_tx.into(), from),
1438 TransactionInfo::default(),
1439 );
1440 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
1441
1442 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1443 assert_eq!(tx_env.inner.caller, from);
1444 assert_eq!(tx_env.inner.nonce, 42);
1445 assert_eq!(tx_env.inner.gas_limit, 21001);
1446 assert_eq!(tx_env.inner.value, U256::from(101));
1447 assert_eq!(tx_env.fee_token, None);
1448 }
1449
1450 #[test]
1451 fn from_any_rpc_transaction_for_tempo_aa() {
1452 let from = Address::random();
1453 let fee_token = Some(Address::random());
1454 let tempo_tx = TempoTransaction {
1455 chain_id: 42431,
1456 nonce: 42,
1457 gas_limit: 424242,
1458 fee_token,
1459 nonce_key: U256::from(4242),
1460 valid_after: NonZeroU64::new(1800000000),
1461 ..Default::default()
1462 };
1463 let aa_signed = AASigned::new_unhashed(
1464 tempo_tx,
1465 TempoSignature::Primitive(PrimitiveSignature::Secp256k1(Signature::new(
1466 U256::ZERO,
1467 U256::ZERO,
1468 false,
1469 ))),
1470 );
1471
1472 let rpc_tx = RpcTransaction::from_transaction(
1475 Recovered::new_unchecked(TempoTxEnvelope::AA(aa_signed), from),
1476 TransactionInfo::default(),
1477 );
1478 let json = serde_json::to_value(&rpc_tx).unwrap();
1479 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
1480
1481 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1482 assert_eq!(tx_env.inner.caller, from);
1483 assert_eq!(tx_env.inner.nonce, 42);
1484 assert_eq!(tx_env.inner.gas_limit, 424242);
1485 assert_eq!(tx_env.inner.chain_id, Some(42431));
1486 assert_eq!(tx_env.fee_token, fee_token);
1487 }
1488
1489 #[cfg(feature = "optimism")]
1490 mod optimism {
1491 use super::*;
1492 use alloy_consensus::Sealed;
1493 use alloy_eips::eip2718::Encodable2718;
1494 use alloy_op_evm::{OpEvmFactory, OpTx};
1495 use op_alloy_consensus::{OpTxEnvelope, TxDeposit, transaction::OpTransactionInfo};
1496 use op_alloy_rpc_types::Transaction as OpRpcTransaction;
1497 use op_revm::OpSpecId;
1498
1499 #[test]
1500 fn op_evm_foundry_context_ext_implementation() {
1501 let mut evm =
1502 OpEvmFactory::<OpTx>::default().create_evm(EmptyDB::default(), EvmEnv::default());
1503
1504 evm.ctx_mut().block_mut().set_number(U256::from(123));
1506 assert_eq!(evm.ctx().block().number(), U256::from(123));
1507
1508 evm.ctx_mut().tx_mut().set_nonce(99);
1510 assert_eq!(evm.ctx().tx().nonce(), 99);
1511
1512 evm.ctx_mut().cfg_mut().spec = OpSpecId::JOVIAN;
1514 assert_eq!(evm.ctx().cfg().spec, OpSpecId::JOVIAN);
1515
1516 let tx_env = evm.ctx().tx_clone();
1518 evm.ctx_mut().set_tx(tx_env);
1519 let evm_env = evm.ctx().evm_clone();
1520 evm.ctx_mut().set_evm(evm_env);
1521 }
1522
1523 #[test]
1524 fn from_any_rpc_transaction_for_op() {
1525 let from = Address::random();
1526 let signed_tx = make_signed_eip1559();
1527
1528 let rpc_tx = RpcTransaction::from_transaction(
1530 Recovered::new_unchecked(signed_tx.into(), from),
1531 TransactionInfo::default(),
1532 );
1533 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
1534 let expected_base = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1535
1536 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
1537 assert_eq!(op_tx_env.base, expected_base);
1538 assert_eq!(
1541 op_tx_env.enveloped_tx,
1542 Some(any_tx.as_envelope().unwrap().encoded_2718().into())
1543 );
1544 }
1545
1546 #[test]
1547 fn from_any_rpc_transaction_for_op_deposit() {
1548 let from = Address::random();
1549 let source_hash = B256::random();
1550 let deposit = TxDeposit {
1551 source_hash,
1552 from,
1553 to: TxKind::Call(Address::with_last_byte(0xCC)),
1554 mint: 1111,
1555 value: U256::from(200),
1556 gas_limit: 21000,
1557 is_system_transaction: true,
1558 input: Default::default(),
1559 };
1560
1561 let op_rpc_tx = OpRpcTransaction::from_transaction(
1564 Recovered::new_unchecked(OpTxEnvelope::Deposit(Sealed::new(deposit)), from),
1565 OpTransactionInfo::default(),
1566 );
1567 let json = serde_json::to_value(&op_rpc_tx).unwrap();
1568 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
1569
1570 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
1571 assert_eq!(op_tx_env.base.caller, from);
1572 assert_eq!(op_tx_env.base.kind, TxKind::Call(Address::with_last_byte(0xCC)));
1573 assert_eq!(op_tx_env.base.value, U256::from(200));
1574 assert_eq!(op_tx_env.base.gas_limit, 21000);
1575 assert_eq!(op_tx_env.deposit.source_hash, source_hash);
1576 assert_eq!(op_tx_env.deposit.mint, Some(1111));
1577 assert!(op_tx_env.deposit.is_system_transaction);
1578 }
1579 }
1580}