Skip to main content

foundry_primitives/network/
transaction.rs

1use alloy_consensus::{
2    BlobTransactionSidecar, BlobTransactionSidecarEip7594, BlobTransactionSidecarVariant,
3};
4use alloy_network::{AnyNetwork, Ethereum, Network, TransactionBuilder};
5use alloy_primitives::{Address, B256, Signature, U256};
6use alloy_rpc_types::SignedAuthorization;
7use tempo_alloy::TempoNetwork;
8
9/// Composite transaction builder trait for Foundry transactions.
10///
11/// This extends the base `TransactionBuilder` trait with the same methods as
12/// [`alloy_network::TransactionBuilder4844`] for handling blob transaction sidecars, and
13/// [`alloy_network::TransactionBuilder7702`] for handling EIP-7702 authorization lists.
14///
15/// By default, all methods have no-op implementations, so this can be implemented for any Network.
16///
17/// If the Network supports Eip4844 blob transactions implement these methods:
18/// - [`FoundryTransactionBuilder::max_fee_per_blob_gas`]
19/// - [`FoundryTransactionBuilder::set_max_fee_per_blob_gas`]
20/// - [`FoundryTransactionBuilder::blob_versioned_hashes`]
21/// - [`FoundryTransactionBuilder::set_blob_versioned_hashes`]
22/// - [`FoundryTransactionBuilder::blob_sidecar`]
23/// - [`FoundryTransactionBuilder::set_blob_sidecar`]
24///
25/// If the Network supports EIP-7702 authorization lists, implement these methods:
26/// - [`FoundryTransactionBuilder::authorization_list`]
27/// - [`FoundryTransactionBuilder::set_authorization_list`]
28///
29/// If the Network supports Tempo transactions, implement these methods:
30/// - [`FoundryTransactionBuilder::set_fee_token`]
31/// - [`FoundryTransactionBuilder::set_nonce_key`]
32/// - [`FoundryTransactionBuilder::set_key_id`]
33/// - [`FoundryTransactionBuilder::set_valid_before`]
34/// - [`FoundryTransactionBuilder::set_valid_after`]
35/// - [`FoundryTransactionBuilder::set_fee_payer_signature`]
36pub trait FoundryTransactionBuilder<N: Network>: TransactionBuilder<N> {
37    /// Reset gas limit
38    fn reset_gas_limit(&mut self);
39
40    /// Get the max fee per blob gas for the transaction.
41    fn max_fee_per_blob_gas(&self) -> Option<u128> {
42        None
43    }
44
45    /// Set the max fee per blob gas for the transaction.
46    fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
47
48    /// Builder-pattern method for setting max fee per blob gas.
49    fn with_max_fee_per_blob_gas(mut self, max_fee_per_blob_gas: u128) -> Self {
50        self.set_max_fee_per_blob_gas(max_fee_per_blob_gas);
51        self
52    }
53
54    /// Gets the EIP-4844 blob versioned hashes of the transaction.
55    ///
56    /// These may be set independently of the sidecar, e.g. when the sidecar
57    /// has been pruned but the hashes are still needed for `eth_call`.
58    fn blob_versioned_hashes(&self) -> Option<&[B256]> {
59        None
60    }
61
62    /// Sets the EIP-4844 blob versioned hashes of the transaction.
63    fn set_blob_versioned_hashes(&mut self, _hashes: Vec<B256>) {}
64
65    /// Builder-pattern method for setting the EIP-4844 blob versioned hashes.
66    fn with_blob_versioned_hashes(mut self, hashes: Vec<B256>) -> Self {
67        self.set_blob_versioned_hashes(hashes);
68        self
69    }
70
71    /// Gets the blob sidecar (either EIP-4844 or EIP-7594 variant) of the transaction.
72    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {
73        None
74    }
75
76    /// Sets the blob sidecar (either EIP-4844 or EIP-7594 variant) of the transaction.
77    ///
78    /// Note: This will also set the versioned blob hashes accordingly:
79    /// [BlobTransactionSidecarVariant::versioned_hashes]
80    fn set_blob_sidecar(&mut self, _sidecar: BlobTransactionSidecarVariant) {}
81
82    /// Builder-pattern method for setting the blob sidecar of the transaction.
83    fn with_blob_sidecar(mut self, sidecar: BlobTransactionSidecarVariant) -> Self {
84        self.set_blob_sidecar(sidecar);
85        self
86    }
87
88    /// Gets the EIP-4844 blob sidecar if the current sidecar is of that variant.
89    fn blob_sidecar_4844(&self) -> Option<&BlobTransactionSidecar> {
90        self.blob_sidecar().and_then(|s| s.as_eip4844())
91    }
92
93    /// Sets the EIP-4844 blob sidecar of the transaction.
94    fn set_blob_sidecar_4844(&mut self, sidecar: BlobTransactionSidecar) {
95        self.set_blob_sidecar(BlobTransactionSidecarVariant::Eip4844(sidecar));
96    }
97
98    /// Builder-pattern method for setting the EIP-4844 blob sidecar of the transaction.
99    fn with_blob_sidecar_4844(mut self, sidecar: BlobTransactionSidecar) -> Self {
100        self.set_blob_sidecar_4844(sidecar);
101        self
102    }
103
104    /// Gets the EIP-7594 blob sidecar if the current sidecar is of that variant.
105    fn blob_sidecar_7594(&self) -> Option<&BlobTransactionSidecarEip7594> {
106        self.blob_sidecar().and_then(|s| s.as_eip7594())
107    }
108
109    /// Sets the EIP-7594 blob sidecar of the transaction.
110    fn set_blob_sidecar_7594(&mut self, sidecar: BlobTransactionSidecarEip7594) {
111        self.set_blob_sidecar(BlobTransactionSidecarVariant::Eip7594(sidecar));
112    }
113
114    /// Builder-pattern method for setting the EIP-7594 blob sidecar of the transaction.
115    fn with_blob_sidecar_7594(mut self, sidecar: BlobTransactionSidecarEip7594) -> Self {
116        self.set_blob_sidecar_7594(sidecar);
117        self
118    }
119
120    /// Get the EIP-7702 authorization list for the transaction.
121    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {
122        None
123    }
124
125    /// Sets the EIP-7702 authorization list.
126    fn set_authorization_list(&mut self, _authorization_list: Vec<SignedAuthorization>) {}
127
128    /// Builder-pattern method for setting the authorization list.
129    fn with_authorization_list(mut self, authorization_list: Vec<SignedAuthorization>) -> Self {
130        self.set_authorization_list(authorization_list);
131        self
132    }
133
134    /// Get the fee token for a Tempo transaction.
135    fn fee_token(&self) -> Option<Address> {
136        None
137    }
138
139    /// Set the fee token for a Tempo transaction.
140    fn set_fee_token(&mut self, _fee_token: Address) {}
141
142    /// Builder-pattern method for setting the Tempo fee token.
143    fn with_fee_token(mut self, fee_token: Address) -> Self {
144        self.set_fee_token(fee_token);
145        self
146    }
147
148    /// Get the 2D nonce key for a Tempo transaction.
149    fn nonce_key(&self) -> Option<U256> {
150        None
151    }
152
153    /// Set the 2D nonce key for the Tempo transaction.
154    fn set_nonce_key(&mut self, _nonce_key: U256) {}
155
156    /// Builder-pattern method for setting a 2D nonce key for a Tempo transaction.
157    fn with_nonce_key(mut self, nonce_key: U256) -> Self {
158        self.set_nonce_key(nonce_key);
159        self
160    }
161
162    /// Get the access key ID for a Tempo transaction.
163    fn key_id(&self) -> Option<Address> {
164        None
165    }
166
167    /// Set the access key ID for a Tempo transaction.
168    ///
169    /// Used during gas estimation to override the key_id that would normally be
170    /// recovered from the signature.
171    fn set_key_id(&mut self, _key_id: Address) {}
172
173    /// Builder-pattern method for setting the Tempo access key ID.
174    fn with_key_id(mut self, key_id: Address) -> Self {
175        self.set_key_id(key_id);
176        self
177    }
178
179    /// Get the valid_before timestamp for a Tempo expiring nonce transaction.
180    fn valid_before(&self) -> Option<u64> {
181        None
182    }
183
184    /// Set the valid_before timestamp for a Tempo expiring nonce transaction.
185    fn set_valid_before(&mut self, _valid_before: u64) {}
186
187    /// Builder-pattern method for setting the valid_before timestamp.
188    fn with_valid_before(mut self, valid_before: u64) -> Self {
189        self.set_valid_before(valid_before);
190        self
191    }
192
193    /// Get the valid_after timestamp for a Tempo expiring nonce transaction.
194    fn valid_after(&self) -> Option<u64> {
195        None
196    }
197
198    /// Set the valid_after timestamp for a Tempo expiring nonce transaction.
199    fn set_valid_after(&mut self, _valid_after: u64) {}
200
201    /// Builder-pattern method for setting the valid_after timestamp.
202    fn with_valid_after(mut self, valid_after: u64) -> Self {
203        self.set_valid_after(valid_after);
204        self
205    }
206
207    /// Get the fee payer (sponsor) signature for a Tempo sponsored transaction.
208    fn fee_payer_signature(&self) -> Option<Signature> {
209        None
210    }
211
212    /// Set the fee payer (sponsor) signature for a Tempo sponsored transaction.
213    fn set_fee_payer_signature(&mut self, _signature: Signature) {}
214
215    /// Builder-pattern method for setting the fee payer signature.
216    fn with_fee_payer_signature(mut self, signature: Signature) -> Self {
217        self.set_fee_payer_signature(signature);
218        self
219    }
220
221    /// Computes the sponsor (fee payer) signature hash for this transaction.
222    ///
223    /// This builds an unsigned consensus-level transaction from the request and computes
224    /// the hash that a sponsor needs to sign. Returns `None` for networks that don't
225    /// support sponsored transactions.
226    fn compute_sponsor_hash(&self, _from: Address) -> Option<B256> {
227        None
228    }
229}
230
231impl FoundryTransactionBuilder<Ethereum> for <Ethereum as Network>::TransactionRequest {
232    fn reset_gas_limit(&mut self) {
233        self.gas = None;
234    }
235
236    fn max_fee_per_blob_gas(&self) -> Option<u128> {
237        self.max_fee_per_blob_gas
238    }
239
240    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
241        self.max_fee_per_blob_gas = Some(max_fee_per_blob_gas);
242    }
243
244    fn blob_versioned_hashes(&self) -> Option<&[B256]> {
245        self.blob_versioned_hashes.as_deref()
246    }
247
248    fn set_blob_versioned_hashes(&mut self, hashes: Vec<B256>) {
249        self.blob_versioned_hashes = Some(hashes);
250    }
251
252    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {
253        self.sidecar.as_ref()
254    }
255
256    fn set_blob_sidecar(&mut self, sidecar: BlobTransactionSidecarVariant) {
257        self.sidecar = Some(sidecar);
258        self.populate_blob_hashes();
259    }
260
261    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {
262        self.authorization_list.as_ref()
263    }
264
265    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {
266        self.authorization_list = Some(authorization_list);
267    }
268}
269
270impl FoundryTransactionBuilder<AnyNetwork> for <AnyNetwork as Network>::TransactionRequest {
271    fn reset_gas_limit(&mut self) {
272        self.gas = None;
273    }
274
275    fn max_fee_per_blob_gas(&self) -> Option<u128> {
276        self.max_fee_per_blob_gas
277    }
278
279    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
280        self.max_fee_per_blob_gas = Some(max_fee_per_blob_gas);
281    }
282
283    fn blob_versioned_hashes(&self) -> Option<&[B256]> {
284        self.blob_versioned_hashes.as_deref()
285    }
286
287    fn set_blob_versioned_hashes(&mut self, hashes: Vec<B256>) {
288        self.blob_versioned_hashes = Some(hashes);
289    }
290
291    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {
292        self.sidecar.as_ref()
293    }
294
295    fn set_blob_sidecar(&mut self, sidecar: BlobTransactionSidecarVariant) {
296        self.sidecar = Some(sidecar);
297        self.populate_blob_hashes();
298    }
299
300    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {
301        self.authorization_list.as_ref()
302    }
303
304    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {
305        self.authorization_list = Some(authorization_list);
306    }
307}
308
309impl FoundryTransactionBuilder<TempoNetwork> for <TempoNetwork as Network>::TransactionRequest {
310    fn reset_gas_limit(&mut self) {
311        self.gas = None;
312    }
313
314    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {
315        self.authorization_list.as_ref()
316    }
317
318    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {
319        self.authorization_list = Some(authorization_list);
320    }
321
322    fn fee_token(&self) -> Option<Address> {
323        self.fee_token
324    }
325
326    fn set_fee_token(&mut self, fee_token: Address) {
327        self.fee_token = Some(fee_token);
328    }
329
330    fn nonce_key(&self) -> Option<U256> {
331        self.nonce_key
332    }
333
334    fn set_nonce_key(&mut self, nonce_key: U256) {
335        self.nonce_key = Some(nonce_key);
336    }
337
338    fn key_id(&self) -> Option<Address> {
339        self.key_id
340    }
341
342    fn set_key_id(&mut self, key_id: Address) {
343        self.key_id = Some(key_id);
344    }
345
346    fn valid_before(&self) -> Option<u64> {
347        self.valid_before
348    }
349
350    fn set_valid_before(&mut self, valid_before: u64) {
351        self.valid_before = Some(valid_before);
352    }
353
354    fn valid_after(&self) -> Option<u64> {
355        self.valid_after
356    }
357
358    fn set_valid_after(&mut self, valid_after: u64) {
359        self.valid_after = Some(valid_after);
360    }
361
362    fn fee_payer_signature(&self) -> Option<Signature> {
363        self.fee_payer_signature
364    }
365
366    fn set_fee_payer_signature(&mut self, signature: Signature) {
367        self.fee_payer_signature = Some(signature);
368    }
369
370    fn compute_sponsor_hash(&self, from: Address) -> Option<B256> {
371        let tx = self.clone().build_aa().ok()?;
372        Some(tx.fee_payer_signature_hash(from))
373    }
374}