anvil_core/eth/transaction/
mod.rs1use alloy_consensus::{
3 Transaction, Typed2718,
4 crypto::RecoveryError,
5 transaction::{SignerRecoverable, TxHashRef},
6};
7
8use alloy_eips::eip2718::Encodable2718;
9use alloy_primitives::{Address, B256, Bytes, TxHash};
10use alloy_rlp::{Decodable, Encodable};
11use bytes::BufMut;
12use foundry_evm::traces::CallTraceNode;
13use foundry_primitives::FoundryTxEnvelope;
14use revm::interpreter::InstructionResult;
15use serde::{Deserialize, Serialize};
16use std::ops::Deref;
17
18#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
23pub struct MaybeImpersonatedTransaction<T> {
24 transaction: T,
25 impersonated_sender: Option<Address>,
26}
27
28impl<T: Typed2718> Typed2718 for MaybeImpersonatedTransaction<T> {
29 fn ty(&self) -> u8 {
30 self.transaction.ty()
31 }
32}
33
34impl<T> MaybeImpersonatedTransaction<T> {
35 pub fn new(transaction: T) -> Self {
37 Self { transaction, impersonated_sender: None }
38 }
39
40 pub fn impersonated(transaction: T, impersonated_sender: Address) -> Self {
42 Self { transaction, impersonated_sender: Some(impersonated_sender) }
43 }
44
45 pub fn is_impersonated(&self) -> bool {
47 self.impersonated_sender.is_some()
48 }
49
50 pub fn into_inner(self) -> T {
52 self.transaction
53 }
54}
55
56impl<T: SignerRecoverable + TxHashRef + Encodable> MaybeImpersonatedTransaction<T> {
57 pub fn recover(&self) -> Result<Address, RecoveryError> {
59 if let Some(sender) = self.impersonated_sender {
60 return Ok(sender);
61 }
62 self.transaction.recover_signer()
63 }
64
65 pub fn hash(&self) -> B256 {
70 if let Some(sender) = self.impersonated_sender {
71 let mut buffer = Vec::new();
72 self.transaction.encode(&mut buffer);
73 buffer.extend_from_slice(sender.as_ref());
74 return B256::from_slice(alloy_primitives::utils::keccak256(&buffer).as_slice());
75 }
76 *self.transaction.tx_hash()
77 }
78}
79
80impl<T: Encodable2718> Encodable2718 for MaybeImpersonatedTransaction<T> {
81 fn encode_2718_len(&self) -> usize {
82 self.transaction.encode_2718_len()
83 }
84
85 fn encode_2718(&self, out: &mut dyn BufMut) {
86 self.transaction.encode_2718(out)
87 }
88}
89
90impl<T: Encodable> Encodable for MaybeImpersonatedTransaction<T> {
91 fn encode(&self, out: &mut dyn bytes::BufMut) {
92 self.transaction.encode(out)
93 }
94}
95
96impl From<MaybeImpersonatedTransaction<Self>> for FoundryTxEnvelope {
97 fn from(value: MaybeImpersonatedTransaction<Self>) -> Self {
98 value.transaction
99 }
100}
101
102impl From<FoundryTxEnvelope> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {
103 fn from(value: FoundryTxEnvelope) -> Self {
104 Self::new(value)
105 }
106}
107
108impl<T: Decodable> Decodable for MaybeImpersonatedTransaction<T> {
109 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
110 T::decode(buf).map(Self::new)
111 }
112}
113
114impl<T> AsRef<T> for MaybeImpersonatedTransaction<T> {
115 fn as_ref(&self) -> &T {
116 &self.transaction
117 }
118}
119
120impl<T> Deref for MaybeImpersonatedTransaction<T> {
121 type Target = T;
122
123 fn deref(&self) -> &Self::Target {
124 &self.transaction
125 }
126}
127
128#[derive(Clone, Debug, PartialEq, Eq)]
130pub struct PendingTransaction<T> {
131 pub transaction: MaybeImpersonatedTransaction<T>,
133 sender: Address,
135 hash: TxHash,
137}
138
139impl<T> PendingTransaction<T> {
140 pub fn hash(&self) -> &TxHash {
141 &self.hash
142 }
143
144 pub fn sender(&self) -> &Address {
145 &self.sender
146 }
147}
148
149impl<T: SignerRecoverable + TxHashRef + Encodable> PendingTransaction<T> {
150 pub fn new(transaction: T) -> Result<Self, RecoveryError> {
151 let transaction = MaybeImpersonatedTransaction::new(transaction);
152 let sender = transaction.recover()?;
153 let hash = transaction.hash();
154 Ok(Self { transaction, sender, hash })
155 }
156
157 pub fn with_impersonated(transaction: T, sender: Address) -> Self {
158 let transaction = MaybeImpersonatedTransaction::impersonated(transaction, sender);
159 let hash = transaction.hash();
160 Self { transaction, sender, hash }
161 }
162
163 pub fn from_maybe_impersonated(
165 transaction: MaybeImpersonatedTransaction<T>,
166 ) -> Result<Self, RecoveryError> {
167 if let Some(impersonated) = transaction.impersonated_sender {
168 Ok(Self::with_impersonated(transaction.transaction, impersonated))
169 } else {
170 Self::new(transaction.transaction)
171 }
172 }
173}
174
175impl<T: Transaction> PendingTransaction<T> {
176 pub fn nonce(&self) -> u64 {
177 self.transaction.nonce()
178 }
179}
180
181#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
183pub struct TransactionInfo {
184 pub transaction_hash: B256,
185 pub transaction_index: u64,
186 pub from: Address,
187 pub to: Option<Address>,
188 pub contract_address: Option<Address>,
189 pub traces: Vec<CallTraceNode>,
190 pub exit: InstructionResult,
191 pub out: Option<Bytes>,
192 pub nonce: u64,
193 pub gas_used: u64,
194}