1use alloy_primitives::{Address, B256, Bytes, U256};
4use revm::{
5 context::{Transaction, TxEnv},
6 context_interface::{
7 either::Either,
8 transaction::{AccessList, RecoveredAuthorization, SignedAuthorization},
9 },
10 primitives::TxKind,
11};
12use tempo_revm::TempoTxEnv;
13
14#[cfg(feature = "optimism")]
15use op_revm::transaction::deposit::DEPOSIT_TRANSACTION_TYPE;
16
17pub trait FoundryTransaction: Transaction {
20 fn set_tx_type(&mut self, tx_type: u8);
22
23 fn set_caller(&mut self, caller: Address);
25
26 fn set_gas_limit(&mut self, gas_limit: u64);
28
29 fn set_gas_price(&mut self, gas_price: u128);
31
32 fn set_kind(&mut self, kind: TxKind);
34
35 fn set_value(&mut self, value: U256);
37
38 fn set_data(&mut self, data: Bytes);
40
41 fn set_nonce(&mut self, nonce: u64);
43
44 fn set_chain_id(&mut self, chain_id: Option<u64>);
46
47 fn set_access_list(&mut self, access_list: AccessList);
49
50 fn authorization_list_mut(
52 &mut self,
53 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>>;
54
55 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);
57
58 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);
60
61 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);
63
64 fn set_signed_authorization(&mut self, auth: Vec<SignedAuthorization>) {
66 *self.authorization_list_mut() = auth.into_iter().map(Either::Left).collect();
67 }
68
69 fn enveloped_tx(&self) -> Option<&Bytes> {
73 None
74 }
75
76 fn set_enveloped_tx(&mut self, _bytes: Bytes) {}
78
79 fn source_hash(&self) -> Option<B256> {
81 None
82 }
83
84 fn set_source_hash(&mut self, _source_hash: B256) {}
86
87 fn mint(&self) -> Option<u128> {
89 None
90 }
91
92 fn set_mint(&mut self, _mint: u128) {}
94
95 fn is_system_transaction(&self) -> bool {
97 false
98 }
99
100 fn set_system_transaction(&mut self, _is_system_transaction: bool) {}
102
103 fn is_deposit(&self) -> bool {
105 #[cfg(feature = "optimism")]
106 {
107 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
108 }
109 #[cfg(not(feature = "optimism"))]
110 {
111 false
112 }
113 }
114
115 fn fee_token(&self) -> Option<Address> {
119 None
120 }
121
122 fn set_fee_token(&mut self, _token: Option<Address>) {}
124
125 fn fee_payer(&self) -> Option<Option<Address>> {
127 None
128 }
129
130 fn set_fee_payer(&mut self, _payer: Option<Option<Address>>) {}
132
133 fn is_single_create(&self) -> bool {
135 self.kind().is_create()
136 }
137}
138
139impl FoundryTransaction for TxEnv {
140 fn set_tx_type(&mut self, tx_type: u8) {
141 self.tx_type = tx_type;
142 }
143
144 fn set_caller(&mut self, caller: Address) {
145 self.caller = caller;
146 }
147
148 fn set_gas_limit(&mut self, gas_limit: u64) {
149 self.gas_limit = gas_limit;
150 }
151
152 fn set_gas_price(&mut self, gas_price: u128) {
153 self.gas_price = gas_price;
154 }
155
156 fn set_kind(&mut self, kind: TxKind) {
157 self.kind = kind;
158 }
159
160 fn set_value(&mut self, value: U256) {
161 self.value = value;
162 }
163
164 fn set_data(&mut self, data: Bytes) {
165 self.data = data;
166 }
167
168 fn set_nonce(&mut self, nonce: u64) {
169 self.nonce = nonce;
170 }
171
172 fn set_chain_id(&mut self, chain_id: Option<u64>) {
173 self.chain_id = chain_id;
174 }
175
176 fn set_access_list(&mut self, access_list: AccessList) {
177 self.access_list = access_list;
178 }
179
180 fn authorization_list_mut(
181 &mut self,
182 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
183 &mut self.authorization_list
184 }
185
186 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
187 self.gas_priority_fee = gas_priority_fee;
188 }
189
190 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
191 self.blob_hashes = blob_hashes;
192 }
193
194 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
195 self.max_fee_per_blob_gas = max_fee_per_blob_gas;
196 }
197}
198
199impl FoundryTransaction for TempoTxEnv {
200 fn set_tx_type(&mut self, tx_type: u8) {
201 self.inner.set_tx_type(tx_type);
202 }
203
204 fn set_caller(&mut self, caller: Address) {
205 self.inner.set_caller(caller);
206 }
207
208 fn set_gas_limit(&mut self, gas_limit: u64) {
209 self.inner.set_gas_limit(gas_limit);
210 }
211
212 fn set_gas_price(&mut self, gas_price: u128) {
213 self.inner.set_gas_price(gas_price);
214 }
215
216 fn set_kind(&mut self, kind: TxKind) {
217 self.inner.set_kind(kind);
218 if let Some(call) =
219 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
220 {
221 call.to = kind;
222 }
223 }
224
225 fn set_value(&mut self, value: U256) {
226 self.inner.set_value(value);
227 if let Some(call) =
228 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
229 {
230 call.value = value;
231 }
232 }
233
234 fn set_data(&mut self, data: Bytes) {
235 self.inner.set_data(data.clone());
236 if let Some(call) =
237 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
238 {
239 call.input = data;
240 }
241 }
242
243 fn set_nonce(&mut self, nonce: u64) {
244 self.inner.set_nonce(nonce);
245 }
246
247 fn set_chain_id(&mut self, chain_id: Option<u64>) {
248 self.inner.set_chain_id(chain_id);
249 }
250
251 fn set_access_list(&mut self, access_list: AccessList) {
252 self.inner.set_access_list(access_list);
253 }
254
255 fn authorization_list_mut(
256 &mut self,
257 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
258 self.inner.authorization_list_mut()
259 }
260
261 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
262 self.inner.set_gas_priority_fee(gas_priority_fee);
263 }
264
265 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
266
267 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
268
269 fn fee_token(&self) -> Option<Address> {
270 self.fee_token
271 }
272
273 fn set_fee_token(&mut self, token: Option<Address>) {
274 self.fee_token = token;
275 }
276
277 fn fee_payer(&self) -> Option<Option<Address>> {
278 self.fee_payer
279 }
280
281 fn set_fee_payer(&mut self, payer: Option<Option<Address>>) {
282 self.fee_payer = payer;
283 }
284
285 fn is_single_create(&self) -> bool {
286 self.kind().is_create()
287 && self.tempo_tx_env.as_ref().is_none_or(|env| env.aa_calls.len() == 1)
288 }
289}
290
291#[cfg(feature = "base")]
292mod base {
293 use super::*;
294 use base_common_evm::{BaseTransaction, BaseTxTr, DEPOSIT_TRANSACTION_TYPE};
295
296 impl<TX: FoundryTransaction> FoundryTransaction for BaseTransaction<TX> {
297 fn set_tx_type(&mut self, tx_type: u8) {
298 self.base.set_tx_type(tx_type);
299 }
300
301 fn set_caller(&mut self, caller: Address) {
302 self.base.set_caller(caller);
303 }
304
305 fn set_gas_limit(&mut self, gas_limit: u64) {
306 self.base.set_gas_limit(gas_limit);
307 }
308
309 fn set_gas_price(&mut self, gas_price: u128) {
310 self.base.set_gas_price(gas_price);
311 }
312
313 fn set_kind(&mut self, kind: TxKind) {
314 self.base.set_kind(kind);
315 }
316
317 fn set_value(&mut self, value: U256) {
318 self.base.set_value(value);
319 }
320
321 fn set_data(&mut self, data: Bytes) {
322 self.base.set_data(data);
323 }
324
325 fn set_nonce(&mut self, nonce: u64) {
326 self.base.set_nonce(nonce);
327 }
328
329 fn set_chain_id(&mut self, chain_id: Option<u64>) {
330 self.base.set_chain_id(chain_id);
331 }
332
333 fn set_access_list(&mut self, access_list: AccessList) {
334 self.base.set_access_list(access_list);
335 }
336
337 fn authorization_list_mut(
338 &mut self,
339 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
340 self.base.authorization_list_mut()
341 }
342
343 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
344 self.base.set_gas_priority_fee(gas_priority_fee);
345 }
346
347 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
348 self.base.set_blob_hashes(blob_hashes);
349 }
350
351 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
352 self.base.set_max_fee_per_blob_gas(max_fee_per_blob_gas);
353 }
354
355 fn enveloped_tx(&self) -> Option<&Bytes> {
356 BaseTxTr::enveloped_tx(self)
357 }
358
359 fn set_enveloped_tx(&mut self, bytes: Bytes) {
360 self.enveloped_tx = Some(bytes);
361 }
362
363 fn source_hash(&self) -> Option<B256> {
364 BaseTxTr::source_hash(self)
365 }
366
367 fn set_source_hash(&mut self, source_hash: B256) {
368 self.deposit.source_hash = source_hash;
369 }
370
371 fn mint(&self) -> Option<u128> {
372 BaseTxTr::mint(self)
373 }
374
375 fn set_mint(&mut self, mint: u128) {
376 self.deposit.mint = Some(mint);
377 }
378
379 fn is_system_transaction(&self) -> bool {
380 BaseTxTr::is_system_transaction(self)
381 }
382
383 fn set_system_transaction(&mut self, is_system_transaction: bool) {
384 self.deposit.is_system_transaction = is_system_transaction;
385 }
386
387 fn is_deposit(&self) -> bool {
388 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
389 }
390 }
391}
392
393#[cfg(feature = "optimism")]
394mod optimism {
395 use super::*;
396 use alloy_op_evm::OpTx;
397 use op_revm::{OpTransaction, transaction::OpTxTr};
398
399 impl<TX: FoundryTransaction> FoundryTransaction for OpTransaction<TX> {
400 fn set_tx_type(&mut self, tx_type: u8) {
401 self.base.set_tx_type(tx_type);
402 }
403
404 fn set_caller(&mut self, caller: Address) {
405 self.base.set_caller(caller);
406 }
407
408 fn set_gas_limit(&mut self, gas_limit: u64) {
409 self.base.set_gas_limit(gas_limit);
410 }
411
412 fn set_gas_price(&mut self, gas_price: u128) {
413 self.base.set_gas_price(gas_price);
414 }
415
416 fn set_kind(&mut self, kind: TxKind) {
417 self.base.set_kind(kind);
418 }
419
420 fn set_value(&mut self, value: U256) {
421 self.base.set_value(value);
422 }
423
424 fn set_data(&mut self, data: Bytes) {
425 self.base.set_data(data);
426 }
427
428 fn set_nonce(&mut self, nonce: u64) {
429 self.base.set_nonce(nonce);
430 }
431
432 fn set_chain_id(&mut self, chain_id: Option<u64>) {
433 self.base.set_chain_id(chain_id);
434 }
435
436 fn set_access_list(&mut self, access_list: AccessList) {
437 self.base.set_access_list(access_list);
438 }
439
440 fn authorization_list_mut(
441 &mut self,
442 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
443 self.base.authorization_list_mut()
444 }
445
446 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
447 self.base.set_gas_priority_fee(gas_priority_fee);
448 }
449
450 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
451
452 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
453
454 fn enveloped_tx(&self) -> Option<&Bytes> {
455 OpTxTr::enveloped_tx(self)
456 }
457
458 fn set_enveloped_tx(&mut self, bytes: Bytes) {
459 self.enveloped_tx = Some(bytes);
460 }
461
462 fn source_hash(&self) -> Option<B256> {
463 OpTxTr::source_hash(self)
464 }
465
466 fn set_source_hash(&mut self, source_hash: B256) {
467 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
468 self.deposit.source_hash = source_hash;
469 }
470 }
471
472 fn mint(&self) -> Option<u128> {
473 OpTxTr::mint(self)
474 }
475
476 fn set_mint(&mut self, mint: u128) {
477 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
478 self.deposit.mint = Some(mint);
479 }
480 }
481
482 fn is_system_transaction(&self) -> bool {
483 OpTxTr::is_system_transaction(self)
484 }
485
486 fn set_system_transaction(&mut self, is_system_transaction: bool) {
487 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
488 self.deposit.is_system_transaction = is_system_transaction;
489 }
490 }
491 }
492
493 impl FoundryTransaction for OpTx {
494 fn set_tx_type(&mut self, tx_type: u8) {
495 self.0.set_tx_type(tx_type);
496 }
497
498 fn set_caller(&mut self, caller: Address) {
499 self.0.set_caller(caller);
500 }
501
502 fn set_gas_limit(&mut self, gas_limit: u64) {
503 self.0.set_gas_limit(gas_limit);
504 }
505
506 fn set_gas_price(&mut self, gas_price: u128) {
507 self.0.set_gas_price(gas_price);
508 }
509
510 fn set_kind(&mut self, kind: TxKind) {
511 self.0.set_kind(kind);
512 }
513
514 fn set_value(&mut self, value: U256) {
515 self.0.set_value(value);
516 }
517
518 fn set_data(&mut self, data: Bytes) {
519 self.0.set_data(data);
520 }
521
522 fn set_nonce(&mut self, nonce: u64) {
523 self.0.set_nonce(nonce);
524 }
525
526 fn set_chain_id(&mut self, chain_id: Option<u64>) {
527 self.0.set_chain_id(chain_id);
528 }
529
530 fn set_access_list(&mut self, access_list: AccessList) {
531 self.0.set_access_list(access_list);
532 }
533
534 fn authorization_list_mut(
535 &mut self,
536 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
537 self.0.authorization_list_mut()
538 }
539
540 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
541 self.0.set_gas_priority_fee(gas_priority_fee);
542 }
543
544 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
545
546 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
547
548 fn enveloped_tx(&self) -> Option<&Bytes> {
549 FoundryTransaction::enveloped_tx(&self.0)
550 }
551
552 fn set_enveloped_tx(&mut self, bytes: Bytes) {
553 self.0.set_enveloped_tx(bytes);
554 }
555
556 fn source_hash(&self) -> Option<B256> {
557 FoundryTransaction::source_hash(&self.0)
558 }
559
560 fn set_source_hash(&mut self, source_hash: B256) {
561 self.0.set_source_hash(source_hash);
562 }
563
564 fn mint(&self) -> Option<u128> {
565 FoundryTransaction::mint(&self.0)
566 }
567
568 fn set_mint(&mut self, mint: u128) {
569 self.0.set_mint(mint);
570 }
571
572 fn is_system_transaction(&self) -> bool {
573 FoundryTransaction::is_system_transaction(&self.0)
574 }
575
576 fn set_system_transaction(&mut self, is_system_transaction: bool) {
577 self.0.set_system_transaction(is_system_transaction);
578 }
579 }
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585 use tempo_alloy::primitives::transaction::Call;
586
587 #[test]
588 fn tempo_tx_env_setters_update_aa_call_payload() {
589 let old_to = TxKind::Call(Address::with_last_byte(0xAA));
590 let new_to = TxKind::Create;
591 let new_value = U256::from(123);
592 let new_input = Bytes::from_static(b"local bytecode");
593
594 let mut tx_env = TempoTxEnv {
595 inner: TxEnv {
596 kind: old_to,
597 value: U256::ONE,
598 data: Bytes::from_static(b"original bytecode"),
599 ..Default::default()
600 },
601 tempo_tx_env: Some(Box::new(tempo_revm::TempoBatchCallEnv {
602 aa_calls: vec![Call {
603 to: old_to,
604 value: U256::ONE,
605 input: Bytes::from_static(b"original bytecode"),
606 }],
607 ..Default::default()
608 })),
609 ..Default::default()
610 };
611
612 tx_env.set_kind(new_to);
613 tx_env.set_value(new_value);
614 tx_env.set_data(new_input.clone());
615
616 assert_eq!(tx_env.inner.kind, new_to);
617 assert_eq!(tx_env.inner.value, new_value);
618 assert_eq!(tx_env.inner.data, new_input);
619
620 let call = &tx_env.tempo_tx_env.as_ref().unwrap().aa_calls[0];
621 assert_eq!(call.to, new_to);
622 assert_eq!(call.value, new_value);
623 assert_eq!(call.input, new_input);
624 }
625}