alloy_contract/
call.rs

1use crate::{CallDecoder, Error, EthCall, Result};
2use alloy_consensus::SignableTransaction;
3use alloy_dyn_abi::{DynSolValue, JsonAbiExt};
4use alloy_json_abi::Function;
5use alloy_network::{
6    eip2718::Encodable2718, Ethereum, IntoWallet, Network, TransactionBuilder,
7    TransactionBuilder4844, TransactionBuilderError, TxSigner,
8};
9use alloy_network_primitives::ReceiptResponse;
10use alloy_primitives::{Address, Bytes, ChainId, Signature, TxKind, U256};
11use alloy_provider::{PendingTransactionBuilder, Provider};
12use alloy_rpc_types_eth::{state::StateOverride, AccessList, BlobTransactionSidecar, BlockId};
13use alloy_sol_types::SolCall;
14use std::{self, marker::PhantomData};
15
16// NOTE: The `T` generic here is kept to mitigate breakage with the `sol!` macro.
17// It should always be `()` and has no effect on the implementation.
18
19/// [`CallBuilder`] using a [`SolCall`] type as the call decoder.
20// NOTE: please avoid changing this type due to its use in the `sol!` macro.
21pub type SolCallBuilder<P, C, N = Ethereum> = CallBuilder<P, PhantomData<C>, N>;
22
23/// [`CallBuilder`] using a [`Function`] as the call decoder.
24pub type DynCallBuilder<P, N = Ethereum> = CallBuilder<P, Function, N>;
25
26/// [`CallBuilder`] that does not have a call decoder.
27pub type RawCallBuilder<P, N = Ethereum> = CallBuilder<P, (), N>;
28
29/// A builder for sending a transaction via `eth_sendTransaction`, or calling a contract via
30/// `eth_call`.
31///
32/// The builder can be `.await`ed directly, which is equivalent to invoking [`call`].
33/// Prefer using [`call`] when possible, as `await`ing the builder directly will consume it, and
34/// currently also boxes the future due to type system limitations.
35///
36/// A call builder can currently be instantiated in the following ways:
37/// - by [`sol!`][sol]-generated contract structs' methods (through the `#[sol(rpc)]` attribute)
38///   ([`SolCallBuilder`]);
39/// - by [`ContractInstance`](crate::ContractInstance)'s methods ([`DynCallBuilder`]);
40/// - using [`CallBuilder::new_raw`] ([`RawCallBuilder`]).
41///
42/// Each method represents a different way to decode the output of the contract call.
43///
44/// [`call`]: CallBuilder::call
45///
46/// # Note
47///
48/// This will set [state overrides](https://geth.ethereum.org/docs/rpc/ns-eth#3-object---state-override-set)
49/// for `eth_call`, but this is not supported by all clients.
50///
51/// # Examples
52///
53/// Using [`sol!`][sol]:
54///
55/// ```no_run
56/// # async fn test<P: alloy_provider::Provider>(provider: P) -> Result<(), Box<dyn std::error::Error>> {
57/// use alloy_contract::SolCallBuilder;
58/// use alloy_primitives::{Address, U256};
59/// use alloy_sol_types::sol;
60///
61/// sol! {
62///     #[sol(rpc)] // <-- Important!
63///     contract MyContract {
64///         function doStuff(uint a, bool b) public returns(address c, bytes32 d);
65///     }
66/// }
67///
68/// # stringify!(
69/// let provider = ...;
70/// # );
71/// let address = Address::ZERO;
72/// let contract = MyContract::new(address, &provider);
73///
74/// // Through `contract.<function_name>(args...)`
75/// let a = U256::ZERO;
76/// let b = true;
77/// let builder: SolCallBuilder<_, MyContract::doStuffCall, _> = contract.doStuff(a, b);
78/// let MyContract::doStuffReturn { c: _, d: _ } = builder.call().await?;
79///
80/// // Through `contract.call_builder(&<FunctionCall { args... }>)`:
81/// // (note that this is discouraged because it's inherently less type-safe)
82/// let call = MyContract::doStuffCall { a, b };
83/// let builder: SolCallBuilder<_, MyContract::doStuffCall, _> = contract.call_builder(&call);
84/// let MyContract::doStuffReturn { c: _, d: _ } = builder.call().await?;
85/// # Ok(())
86/// # }
87/// ```
88///
89/// Using [`ContractInstance`](crate::ContractInstance):
90///
91/// ```no_run
92/// # async fn test<P: alloy_provider::Provider>(provider: P, dynamic_abi: alloy_json_abi::JsonAbi) -> Result<(), Box<dyn std::error::Error>> {
93/// use alloy_primitives::{Address, Bytes, U256};
94/// use alloy_dyn_abi::DynSolValue;
95/// use alloy_contract::{CallBuilder, ContractInstance, DynCallBuilder, Interface, RawCallBuilder};
96///
97/// # stringify!(
98/// let dynamic_abi: JsonAbi = ...;
99/// # );
100/// let interface = Interface::new(dynamic_abi);
101///
102/// # stringify!(
103/// let provider = ...;
104/// # );
105/// let address = Address::ZERO;
106/// let contract: ContractInstance<_, _> = interface.connect(address, &provider);
107///
108/// // Build and call the function:
109/// let call_builder: DynCallBuilder<_, _> = contract.function("doStuff", &[U256::ZERO.into(), true.into()])?;
110/// let result: Vec<DynSolValue> = call_builder.call().await?;
111///
112/// // You can also decode the output manually. Get the raw bytes:
113/// let raw_result: Bytes = call_builder.call_raw().await?;
114/// // Or, equivalently:
115/// let raw_builder: RawCallBuilder<_, _> = call_builder.clone().clear_decoder();
116/// let raw_result: Bytes = raw_builder.call().await?;
117/// // Decode the raw bytes:
118/// let decoded_result: Vec<DynSolValue> = call_builder.decode_output(raw_result)?;
119/// # Ok(())
120/// # }
121/// ```
122///
123/// [sol]: alloy_sol_types::sol
124#[derive(Clone)]
125#[must_use = "call builders do nothing unless you `.call`, `.send`, or `.await` them"]
126pub struct CallBuilder<P, D, N: Network = Ethereum> {
127    pub(crate) request: N::TransactionRequest,
128    block: BlockId,
129    state: Option<StateOverride>,
130    /// The provider.
131    // NOTE: This is public due to usage in `sol!`, please avoid changing it.
132    pub provider: P,
133    decoder: D,
134}
135
136impl<P, D, N: Network> CallBuilder<P, D, N> {
137    /// Converts the call builder to the inner transaction request
138    pub fn into_transaction_request(self) -> N::TransactionRequest {
139        self.request
140    }
141
142    /// Builds and returns a RLP-encoded unsigned transaction from the call that can be signed.
143    ///
144    /// ## Example
145    ///
146    /// ```no_run
147    /// # use alloy_provider::ProviderBuilder;
148    /// # use alloy_sol_types::sol;
149    ///
150    /// sol! {
151    ///     #[sol(rpc, bytecode = "0x")]
152    ///    contract Counter {
153    ///        uint128 public counter;
154    ///
155    ///        function increment() external {
156    ///            counter += 1;
157    ///        }
158    ///    }
159    /// }
160    ///
161    /// #[tokio::main]
162    /// async fn main() {
163    ///     let provider = ProviderBuilder::new().connect_anvil_with_wallet();
164    ///
165    ///     let my_contract = Counter::deploy(provider).await.unwrap();
166    ///
167    ///     let call = my_contract.increment();
168    ///
169    ///     let unsigned_raw_tx: Vec<u8> = call.build_unsigned_raw_transaction().unwrap();
170    ///
171    ///     assert!(!unsigned_raw_tx.is_empty())
172    /// }
173    /// ```
174    pub fn build_unsigned_raw_transaction(self) -> Result<Vec<u8>, TransactionBuilderError<N>>
175    where
176        N::UnsignedTx: SignableTransaction<Signature>,
177    {
178        let tx = self.request.build_unsigned().map_err(|e| e.error)?;
179        Ok(tx.encoded_for_signing())
180    }
181
182    /// Build a RLP-encoded signed raw transaction for the call that can be sent to the network
183    /// using [`Provider::send_raw_transaction`].
184    ///
185    /// ## Example
186    ///
187    /// ```no_run
188    /// # use alloy_provider::{ProviderBuilder, Provider};
189    /// # use alloy_sol_types::sol;
190    /// # use alloy_signer_local::PrivateKeySigner;
191    ///
192    /// sol! {
193    ///    #[sol(rpc, bytecode = "0x")]
194    ///   contract Counter {
195    ///      uint128 public counter;
196    ///
197    ///     function increment() external {
198    ///        counter += 1;
199    ///    }
200    ///  }
201    /// }
202    ///
203    /// #[tokio::main]
204    /// async fn main() {
205    ///     let provider = ProviderBuilder::new().connect_anvil_with_wallet();
206    ///
207    ///     let my_contract = Counter::deploy(&provider).await.unwrap();
208    ///
209    ///     let call = my_contract.increment();
210    ///
211    ///     let pk_signer: PrivateKeySigner = "0x..".parse().unwrap();
212    ///     let signed_raw_tx: Vec<u8> = call.build_raw_transaction(pk_signer).await.unwrap();
213    ///
214    ///     let tx = provider.send_raw_transaction(&signed_raw_tx).await.unwrap();
215    /// }
216    /// ```
217    pub async fn build_raw_transaction<S>(
218        self,
219        signer: S,
220    ) -> Result<Vec<u8>, TransactionBuilderError<N>>
221    where
222        S: TxSigner<Signature> + IntoWallet<N>,
223    {
224        let tx = self.request.build(&signer.into_wallet()).await?;
225        Ok(tx.encoded_2718())
226    }
227}
228
229impl<P, D, N: Network> AsRef<N::TransactionRequest> for CallBuilder<P, D, N> {
230    fn as_ref(&self) -> &N::TransactionRequest {
231        &self.request
232    }
233}
234
235// See [`ContractInstance`].
236impl<P: Provider<N>, N: Network> DynCallBuilder<P, N> {
237    pub(crate) fn new_dyn(
238        provider: P,
239        address: &Address,
240        function: &Function,
241        args: &[DynSolValue],
242    ) -> Result<Self> {
243        Ok(Self::new_inner_call(
244            provider,
245            function.abi_encode_input(args)?.into(),
246            function.clone(),
247        )
248        .to(*address))
249    }
250
251    /// Clears the decoder, returning a raw call builder.
252    #[inline]
253    pub fn clear_decoder(self) -> RawCallBuilder<P, N> {
254        RawCallBuilder {
255            request: self.request,
256            block: self.block,
257            state: self.state,
258            provider: self.provider,
259            decoder: (),
260        }
261    }
262}
263
264#[doc(hidden)]
265impl<'a, P: Provider<N>, C: SolCall, N: Network> SolCallBuilder<&'a P, C, N> {
266    // `sol!` macro constructor, see `#[sol(rpc)]`. Not public API.
267    // NOTE: please avoid changing this function due to its use in the `sol!` macro.
268    pub fn new_sol(provider: &'a P, address: &Address, call: &C) -> Self {
269        Self::new_inner_call(provider, call.abi_encode().into(), PhantomData::<C>).to(*address)
270    }
271}
272
273impl<P: Provider<N>, C: SolCall, N: Network> SolCallBuilder<P, C, N> {
274    /// Clears the decoder, returning a raw call builder.
275    #[inline]
276    pub fn clear_decoder(self) -> RawCallBuilder<P, N> {
277        RawCallBuilder {
278            request: self.request,
279            block: self.block,
280            state: self.state,
281            provider: self.provider,
282            decoder: (),
283        }
284    }
285}
286
287impl<P: Provider<N>, N: Network> RawCallBuilder<P, N> {
288    /// Sets the decoder to the provided [`SolCall`].
289    ///
290    /// Converts the raw call builder into a sol call builder.
291    ///
292    /// Note that generally you would want to instantiate a sol call builder directly using the
293    /// `sol!` macro, but this method is provided for flexibility, for example to convert a raw
294    /// deploy call builder into a sol call builder.
295    ///
296    /// # Examples
297    ///
298    /// Decode a return value from a constructor:
299    ///
300    /// ```no_run
301    /// # use alloy_sol_types::sol;
302    /// sol! {
303    ///     // NOTE: This contract is not meant to be deployed on-chain, but rather
304    ///     // used in a static call with its creation code as the call data.
305    ///     #[sol(rpc, bytecode = "34601457602a60e052600161010052604060e0f35b5f80fdfe")]
306    ///     contract MyContract {
307    ///         // The type returned by the constructor.
308    ///         #[derive(Debug, PartialEq)]
309    ///         struct MyStruct {
310    ///             uint64 a;
311    ///             bool b;
312    ///         }
313    ///
314    ///         constructor() {
315    ///             MyStruct memory s = MyStruct(42, true);
316    ///             bytes memory returnData = abi.encode(s);
317    ///             assembly {
318    ///                 return(add(returnData, 0x20), mload(returnData))
319    ///             }
320    ///         }
321    ///
322    ///         // A shim that represents the return value of the constructor.
323    ///         function constructorReturn() external view returns (MyStruct memory s);
324    ///     }
325    /// }
326    ///
327    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
328    /// # stringify!(
329    /// let provider = ...;
330    /// # );
331    /// # let provider = alloy_provider::ProviderBuilder::new().connect_anvil();
332    /// let call_builder = MyContract::deploy_builder(&provider)
333    ///     .with_sol_decoder::<MyContract::constructorReturnCall>();
334    /// let result = call_builder.call().await?;
335    /// assert_eq!(result, MyContract::MyStruct { a: 42, b: true });
336    /// # Ok(())
337    /// # }
338    /// ```
339    #[inline]
340    pub fn with_sol_decoder<C: SolCall>(self) -> SolCallBuilder<P, C, N> {
341        SolCallBuilder {
342            request: self.request,
343            block: self.block,
344            state: self.state,
345            provider: self.provider,
346            decoder: PhantomData::<C>,
347        }
348    }
349}
350
351impl<P: Provider<N>, N: Network> RawCallBuilder<P, N> {
352    /// Creates a new call builder with the provided provider and ABI encoded input.
353    ///
354    /// Will not decode the output of the call, meaning that [`call`](Self::call) will behave the
355    /// same as [`call_raw`](Self::call_raw).
356    #[inline]
357    pub fn new_raw(provider: P, input: Bytes) -> Self {
358        Self::new_inner_call(provider, input, ())
359    }
360
361    /// Creates a new call builder with the provided provider and contract deploy code.
362    ///
363    /// Will not decode the output of the call, meaning that [`call`](Self::call) will behave the
364    /// same as [`call_raw`](Self::call_raw).
365    // NOTE: please avoid changing this function due to its use in the `sol!` macro.
366    pub fn new_raw_deploy(provider: P, input: Bytes) -> Self {
367        Self::new_inner_deploy(provider, input, ())
368    }
369}
370
371impl<P: Provider<N>, D: CallDecoder, N: Network> CallBuilder<P, D, N> {
372    fn new_inner_deploy(provider: P, input: Bytes, decoder: D) -> Self {
373        Self {
374            request: <N::TransactionRequest>::default().with_deploy_code(input),
375            decoder,
376            provider,
377            block: BlockId::default(),
378            state: None,
379        }
380    }
381
382    fn new_inner_call(provider: P, input: Bytes, decoder: D) -> Self {
383        Self {
384            request: <N::TransactionRequest>::default().with_input(input),
385            decoder,
386            provider,
387            block: BlockId::default(),
388            state: None,
389        }
390    }
391
392    /// Sets the `chain_id` field in the transaction to the provided value
393    pub fn chain_id(mut self, chain_id: ChainId) -> Self {
394        self.request.set_chain_id(chain_id);
395        self
396    }
397
398    /// Sets the `from` field in the transaction to the provided value.
399    pub fn from(mut self, from: Address) -> Self {
400        self.request.set_from(from);
401        self
402    }
403
404    /// Sets the transaction request to the provided tx kind.
405    pub fn kind(mut self, to: TxKind) -> Self {
406        self.request.set_kind(to);
407        self
408    }
409
410    /// Sets the `to` field in the transaction to the provided address.
411    pub fn to(mut self, to: Address) -> Self {
412        self.request.set_to(to);
413        self
414    }
415
416    /// Sets the `sidecar` field in the transaction to the provided value.
417    pub fn sidecar(mut self, blob_sidecar: BlobTransactionSidecar) -> Self
418    where
419        N::TransactionRequest: TransactionBuilder4844,
420    {
421        self.request.set_blob_sidecar(blob_sidecar);
422        self
423    }
424
425    /// Uses a Legacy transaction instead of an EIP-1559 one to execute the call
426    pub fn legacy(self) -> Self {
427        todo!()
428    }
429
430    /// Sets the `gas` field in the transaction to the provided value
431    pub fn gas(mut self, gas: u64) -> Self {
432        self.request.set_gas_limit(gas);
433        self
434    }
435
436    /// Sets the `gas_price` field in the transaction to the provided value
437    /// If the internal transaction is an EIP-1559 one, then it sets both
438    /// `max_fee_per_gas` and `max_priority_fee_per_gas` to the same value
439    pub fn gas_price(mut self, gas_price: u128) -> Self {
440        self.request.set_gas_price(gas_price);
441        self
442    }
443
444    /// Sets the `max_fee_per_gas` in the transaction to the provide value
445    pub fn max_fee_per_gas(mut self, max_fee_per_gas: u128) -> Self {
446        self.request.set_max_fee_per_gas(max_fee_per_gas);
447        self
448    }
449
450    /// Sets the `max_priority_fee_per_gas` in the transaction to the provide value
451    pub fn max_priority_fee_per_gas(mut self, max_priority_fee_per_gas: u128) -> Self {
452        self.request.set_max_priority_fee_per_gas(max_priority_fee_per_gas);
453        self
454    }
455
456    /// Sets the `max_fee_per_blob_gas` in the transaction to the provided value
457    pub fn max_fee_per_blob_gas(mut self, max_fee_per_blob_gas: u128) -> Self
458    where
459        N::TransactionRequest: TransactionBuilder4844,
460    {
461        self.request.set_max_fee_per_blob_gas(max_fee_per_blob_gas);
462        self
463    }
464
465    /// Sets the `access_list` in the transaction to the provided value
466    pub fn access_list(mut self, access_list: AccessList) -> Self {
467        self.request.set_access_list(access_list);
468        self
469    }
470
471    /// Sets the `value` field in the transaction to the provided value
472    pub fn value(mut self, value: U256) -> Self {
473        self.request.set_value(value);
474        self
475    }
476
477    /// Sets the `nonce` field in the transaction to the provided value
478    pub fn nonce(mut self, nonce: u64) -> Self {
479        self.request.set_nonce(nonce);
480        self
481    }
482
483    /// Applies a function to the internal transaction request.
484    pub fn map<F>(mut self, f: F) -> Self
485    where
486        F: FnOnce(N::TransactionRequest) -> N::TransactionRequest,
487    {
488        self.request = f(self.request);
489        self
490    }
491
492    /// Sets the `block` field for sending the tx to the chain
493    pub const fn block(mut self, block: BlockId) -> Self {
494        self.block = block;
495        self
496    }
497
498    /// Sets the [state override set](https://geth.ethereum.org/docs/rpc/ns-eth#3-object---state-override-set).
499    ///
500    /// # Note
501    ///
502    /// Not all client implementations will support this as a parameter to `eth_call`.
503    pub fn state(mut self, state: impl Into<StateOverride>) -> Self {
504        self.state = Some(state.into());
505        self
506    }
507
508    /// Returns the underlying transaction's ABI-encoded data.
509    pub fn calldata(&self) -> &Bytes {
510        self.request.input().expect("set in the constructor")
511    }
512
513    /// Returns the estimated gas cost for the underlying transaction to be executed
514    /// If [`state overrides`](Self::state) are set, they will be applied to the gas estimation.
515    pub async fn estimate_gas(&self) -> Result<u64> {
516        let mut estimate = self.provider.estimate_gas(self.request.clone());
517        if let Some(state) = self.state.clone() {
518            estimate = estimate.overrides(state);
519        }
520        estimate.block(self.block).await.map_err(Into::into)
521    }
522
523    /// Queries the blockchain via an `eth_call` without submitting a transaction to the network.
524    /// If [`state overrides`](Self::state) are set, they will be applied to the call.
525    ///
526    /// Returns the decoded the output by using the provided decoder.
527    /// If this is not desired, use [`call_raw`](Self::call_raw) to get the raw output data.
528    #[doc(alias = "eth_call")]
529    #[doc(alias = "call_with_overrides")]
530    pub fn call(&self) -> EthCall<'_, D, N> {
531        self.call_raw().with_decoder(&self.decoder)
532    }
533
534    /// Queries the blockchain via an `eth_call` without submitting a transaction to the network.
535    /// If [`state overrides`](Self::state) are set, they will be applied to the call.
536    ///
537    /// Does not decode the output of the call, returning the raw output data instead.
538    ///
539    /// See [`call`](Self::call) for more information.
540    pub fn call_raw(&self) -> EthCall<'_, (), N> {
541        let call = self.provider.call(self.request.clone()).block(self.block);
542        let call = match self.state.clone() {
543            Some(state) => call.overrides(state),
544            None => call,
545        };
546        call.into()
547    }
548
549    /// Decodes the output of a contract function using the provided decoder.
550    #[inline]
551    pub fn decode_output(&self, data: Bytes) -> Result<D::CallOutput> {
552        self.decoder.abi_decode_output(data)
553    }
554
555    /// Broadcasts the underlying transaction to the network as a deployment transaction, returning
556    /// the address of the deployed contract after the transaction has been confirmed.
557    ///
558    /// Returns an error if the transaction is not a deployment transaction, or if the contract
559    /// address is not found in the deployment transaction’s receipt.
560    ///
561    /// For more fine-grained control over the deployment process, use [`send`](Self::send) instead.
562    ///
563    /// Note that the deployment address can be pre-calculated if the `from` address and `nonce` are
564    /// known using [`calculate_create_address`](Self::calculate_create_address).
565    pub async fn deploy(&self) -> Result<Address> {
566        if !self.request.kind().is_some_and(|to| to.is_create()) {
567            return Err(Error::NotADeploymentTransaction);
568        }
569        let pending_tx = self.send().await?;
570        let receipt = pending_tx.get_receipt().await?;
571        receipt.contract_address().ok_or(Error::ContractNotDeployed)
572    }
573
574    /// Broadcasts the underlying transaction to the network.
575    ///
576    /// Returns a builder for configuring the pending transaction watcher.
577    /// See [`Provider::send_transaction`] for more information.
578    pub async fn send(&self) -> Result<PendingTransactionBuilder<N>> {
579        Ok(self.provider.send_transaction(self.request.clone()).await?)
580    }
581
582    /// Calculates the address that will be created by the transaction, if any.
583    ///
584    /// Returns `None` if the transaction is not a contract creation (the `to` field is set), or if
585    /// the `from` or `nonce` fields are not set.
586    pub fn calculate_create_address(&self) -> Option<Address> {
587        self.request.calculate_create_address()
588    }
589}
590
591impl<P: Clone, D, N: Network> CallBuilder<&P, D, N> {
592    /// Clones the provider and returns a new builder with the cloned provider.
593    pub fn with_cloned_provider(self) -> CallBuilder<P, D, N> {
594        CallBuilder {
595            request: self.request,
596            block: self.block,
597            state: self.state,
598            provider: self.provider.clone(),
599            decoder: self.decoder,
600        }
601    }
602}
603
604impl<P, D: CallDecoder, N: Network> std::fmt::Debug for CallBuilder<P, D, N> {
605    #[inline]
606    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
607        f.debug_struct("CallBuilder")
608            .field("request", &self.request)
609            .field("block", &self.block)
610            .field("state", &self.state)
611            .field("decoder", &self.decoder.as_debug_field())
612            .finish()
613    }
614}
615
616#[cfg(test)]
617mod tests {
618    use super::*;
619    use alloy_consensus::Transaction;
620    use alloy_network::EthereumWallet;
621    use alloy_node_bindings::Anvil;
622    use alloy_primitives::{address, b256, bytes, hex, utils::parse_units, B256};
623    use alloy_provider::{Provider, ProviderBuilder, WalletProvider};
624    use alloy_rpc_types_eth::AccessListItem;
625    use alloy_signer_local::PrivateKeySigner;
626    use alloy_sol_types::sol;
627    use futures::Future;
628
629    #[test]
630    fn empty_constructor() {
631        sol! {
632            #[sol(rpc, bytecode = "6942")]
633            contract EmptyConstructor {
634                constructor();
635            }
636        }
637
638        let provider = ProviderBuilder::new().connect_anvil();
639        let call_builder = EmptyConstructor::deploy_builder(&provider);
640        assert_eq!(*call_builder.calldata(), bytes!("6942"));
641    }
642
643    sol! {
644        // Solc: 0.8.24+commit.e11b9ed9.Linux.g++
645        // Command: solc a.sol --bin --via-ir --optimize --optimize-runs 1
646        #[sol(rpc, bytecode = "60803461006357601f61014838819003918201601f19168301916001600160401b038311848410176100675780849260209460405283398101031261006357518015158091036100635760ff80195f54169116175f5560405160cc908161007c8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60808060405260043610156011575f80fd5b5f3560e01c9081638bf1799f14607a575063b09a261614602f575f80fd5b346076576040366003190112607657602435801515810360765715606f57604060015b81516004356001600160a01b0316815260ff919091166020820152f35b60405f6052565b5f80fd5b346076575f36600319011260765760209060ff5f541615158152f3fea264697066735822122043709781c9bdc30c530978abf5db25a4b4ccfebf989baafd2ba404519a7f7e8264736f6c63430008180033")]
647        contract MyContract {
648            bool public myState;
649
650            constructor(bool myState_) {
651                myState = myState_;
652            }
653
654            function doStuff(uint a, bool b) external pure returns(address c, bytes32 d) {
655                return (address(uint160(a)), bytes32(uint256(b ? 1 : 0)));
656            }
657        }
658    }
659
660    sol! {
661        // Solc: 0.8.24+commit.e11b9ed9.Linux.g++
662        // Command: solc counter.sol --bin --via-ir --optimize --optimize-runs 1
663        #[sol(rpc, bytecode = "608080604052346100155760d4908161001a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c90816361bc221a14607e575063d09de08a14602f575f80fd5b34607a575f366003190112607a575f546001600160801b038082166001018181116066576001600160801b03199092169116175f55005b634e487b7160e01b5f52601160045260245ffd5b5f80fd5b34607a575f366003190112607a575f546001600160801b03168152602090f3fea26469706673582212208b360e442c4bb2a4bbdec007ee24588c7a88e0aa52ac39efac748e5e23eff69064736f6c63430008180033")]
664        contract Counter {
665            uint128 public counter;
666
667            function increment() external {
668                counter += 1;
669            }
670        }
671    }
672
673    /// Creates a new call_builder to test field modifications, taken from [call_encoding]
674    fn build_call_builder() -> CallBuilder<impl Provider, PhantomData<MyContract::doStuffCall>> {
675        let provider = ProviderBuilder::new().connect_anvil();
676        let contract = MyContract::new(Address::ZERO, provider);
677        let call_builder = contract.doStuff(U256::ZERO, true).with_cloned_provider();
678        call_builder
679    }
680
681    #[test]
682    fn change_chain_id() {
683        let call_builder = build_call_builder().chain_id(1337);
684        assert_eq!(
685            call_builder.request.chain_id.expect("chain_id should be set"),
686            1337,
687            "chain_id of request should be '1337'"
688        );
689    }
690
691    #[test]
692    fn change_max_fee_per_gas() {
693        let call_builder = build_call_builder().max_fee_per_gas(42);
694        assert_eq!(
695            call_builder.request.max_fee_per_gas.expect("max_fee_per_gas should be set"),
696            42,
697            "max_fee_per_gas of request should be '42'"
698        );
699    }
700
701    #[test]
702    fn change_max_priority_fee_per_gas() {
703        let call_builder = build_call_builder().max_priority_fee_per_gas(45);
704        assert_eq!(
705            call_builder
706                .request
707                .max_priority_fee_per_gas
708                .expect("max_priority_fee_per_gas should be set"),
709            45,
710            "max_priority_fee_per_gas of request should be '45'"
711        );
712    }
713
714    #[test]
715    fn change_max_fee_per_blob_gas() {
716        let call_builder = build_call_builder().max_fee_per_blob_gas(50);
717        assert_eq!(
718            call_builder.request.max_fee_per_blob_gas.expect("max_fee_per_blob_gas should be set"),
719            50,
720            "max_fee_per_blob_gas of request should be '50'"
721        );
722    }
723
724    #[test]
725    fn change_access_list() {
726        let access_list = AccessList::from(vec![AccessListItem {
727            address: Address::ZERO,
728            storage_keys: vec![B256::ZERO],
729        }]);
730        let call_builder = build_call_builder().access_list(access_list.clone());
731        assert_eq!(
732            call_builder.request.access_list.expect("access_list should be set"),
733            access_list,
734            "Access list of the transaction should have been set to our access list"
735        )
736    }
737
738    #[test]
739    fn call_encoding() {
740        let provider = ProviderBuilder::new().connect_anvil();
741        let contract = MyContract::new(Address::ZERO, &&provider).with_cloned_provider();
742        let call_builder = contract.doStuff(U256::ZERO, true).with_cloned_provider();
743        assert_eq!(
744            *call_builder.calldata(),
745            bytes!(
746                "b09a2616"
747                "0000000000000000000000000000000000000000000000000000000000000000"
748                "0000000000000000000000000000000000000000000000000000000000000001"
749            ),
750        );
751        // Box the future to assert its concrete output type.
752        let _future: Box<dyn Future<Output = Result<MyContract::doStuffReturn>> + Send> =
753            Box::new(async move { call_builder.call().await });
754    }
755
756    #[test]
757    fn deploy_encoding() {
758        let provider = ProviderBuilder::new().connect_anvil();
759        let bytecode = &MyContract::BYTECODE[..];
760        let call_builder = MyContract::deploy_builder(&provider, false);
761        assert_eq!(
762            call_builder.calldata()[..],
763            [
764                bytecode,
765                &hex!("0000000000000000000000000000000000000000000000000000000000000000")[..]
766            ]
767            .concat(),
768        );
769        let call_builder = MyContract::deploy_builder(&provider, true);
770        assert_eq!(
771            call_builder.calldata()[..],
772            [
773                bytecode,
774                &hex!("0000000000000000000000000000000000000000000000000000000000000001")[..]
775            ]
776            .concat(),
777        );
778    }
779
780    #[tokio::test(flavor = "multi_thread")]
781    async fn deploy_and_call() {
782        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
783
784        let expected_address = provider.default_signer_address().create(0);
785        let my_contract = MyContract::deploy(provider, true).await.unwrap();
786        assert_eq!(*my_contract.address(), expected_address);
787
788        let my_state_builder = my_contract.myState();
789        assert_eq!(my_state_builder.calldata()[..], MyContract::myStateCall {}.abi_encode(),);
790        let my_state = my_state_builder.call().await.unwrap();
791        assert!(my_state);
792
793        let do_stuff_builder = my_contract.doStuff(U256::from(0x69), true);
794        assert_eq!(
795            do_stuff_builder.calldata()[..],
796            MyContract::doStuffCall { a: U256::from(0x69), b: true }.abi_encode(),
797        );
798        let result: MyContract::doStuffReturn = do_stuff_builder.call().await.unwrap();
799        assert_eq!(result.c, address!("0000000000000000000000000000000000000069"));
800        assert_eq!(
801            result.d,
802            b256!("0000000000000000000000000000000000000000000000000000000000000001"),
803        );
804    }
805
806    #[tokio::test(flavor = "multi_thread")]
807    async fn deploy_and_call_with_priority() {
808        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
809        let counter_contract = Counter::deploy(provider.clone()).await.unwrap();
810        let max_fee_per_gas: U256 = parse_units("50", "gwei").unwrap().into();
811        let max_priority_fee_per_gas: U256 = parse_units("0.1", "gwei").unwrap().into();
812        let receipt = counter_contract
813            .increment()
814            .max_fee_per_gas(max_fee_per_gas.to())
815            .max_priority_fee_per_gas(max_priority_fee_per_gas.to())
816            .send()
817            .await
818            .expect("Could not send transaction")
819            .get_receipt()
820            .await
821            .expect("Could not get the receipt");
822        let transaction_hash = receipt.transaction_hash;
823        let transaction = provider
824            .get_transaction_by_hash(transaction_hash)
825            .await
826            .expect("failed to fetch tx")
827            .expect("tx not included");
828        assert_eq!(
829            transaction.max_fee_per_gas(),
830            max_fee_per_gas.to::<u128>(),
831            "max_fee_per_gas of the transaction should be set to the right value"
832        );
833        assert_eq!(
834            transaction
835                .max_priority_fee_per_gas()
836                .expect("max_priority_fee_per_gas of the transaction should be set"),
837            max_priority_fee_per_gas.to::<u128>(),
838            "max_priority_fee_per_gas of the transaction should be set to the right value"
839        )
840    }
841
842    sol! {
843        #[sol(rpc, bytecode = "6080604052348015600e575f80fd5b506101448061001c5f395ff3fe60806040526004361061001d575f3560e01c8063785d04f514610021575b5f80fd5b61003461002f3660046100d5565b610036565b005b5f816001600160a01b0316836040515f6040518083038185875af1925050503d805f811461007f576040519150601f19603f3d011682016040523d82523d5f602084013e610084565b606091505b50509050806100d05760405162461bcd60e51b81526020600482015260146024820152734661696c656420746f2073656e64206d6f6e657960601b604482015260640160405180910390fd5b505050565b5f80604083850312156100e6575f80fd5b8235915060208301356001600160a01b0381168114610103575f80fd5b80915050925092905056fea2646970667358221220188e65dcedbc4bd68fdebc795292d5a9bf643385f138383969a28f796ff8858664736f6c63430008190033")]
844        contract SendMoney {
845            function send(uint256 amount, address target) external payable {
846                (bool success, ) = target.call{value: amount}("");
847                require(success, "Failed to send money");
848            }
849        }
850    }
851
852    // <https://github.com/alloy-rs/alloy/issues/1942>
853    #[tokio::test]
854    async fn fill_eth_call() {
855        let anvil = Anvil::new().spawn();
856        let pk: PrivateKeySigner =
857            "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
858
859        let wallet = EthereumWallet::new(pk);
860
861        let wallet_provider =
862            ProviderBuilder::new().wallet(wallet).connect_http(anvil.endpoint_url());
863
864        let contract = SendMoney::deploy(wallet_provider.clone()).await.unwrap();
865
866        let tx = contract
867            .send(U256::from(1000000), Address::with_last_byte(1))
868            .into_transaction_request()
869            .value(U256::from(1000000));
870
871        assert!(tx.from.is_none());
872
873        let std_provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
874        let should_fail = std_provider.estimate_gas(tx.clone()).await.is_err();
875
876        assert!(should_fail);
877
878        let gas = wallet_provider.estimate_gas(tx).await.unwrap();
879
880        assert_eq!(gas, 56555);
881    }
882
883    #[tokio::test]
884    async fn decode_eth_call_ret_bytes() {
885        sol! {
886            #[derive(Debug, PartialEq)]
887            #[sol(rpc, bytecode = "0x6080604052348015600e575f5ffd5b506101578061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80630d1d2c641461002d575b5f5ffd5b61003561004b565b6040516100429190610108565b60405180910390f35b61005361007b565b6040518060400160405280602a67ffffffffffffffff16815260200160011515815250905090565b60405180604001604052805f67ffffffffffffffff1681526020015f151581525090565b5f67ffffffffffffffff82169050919050565b6100bb8161009f565b82525050565b5f8115159050919050565b6100d5816100c1565b82525050565b604082015f8201516100ef5f8501826100b2565b50602082015161010260208501826100cc565b50505050565b5f60408201905061011b5f8301846100db565b9291505056fea264697066735822122039acc87c027f3bddf6806ff9914411d4245bdc708bca36a07138a37b1b98573464736f6c634300081c0033")]
888            contract RetStruct {
889                struct MyStruct {
890                    uint64 a;
891                    bool b;
892                }
893
894                function retStruct() external pure returns (MyStruct memory) {
895                    return MyStruct(42, true);
896                }
897            }
898        }
899
900        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
901
902        let contract = RetStruct::deploy(provider.clone()).await.unwrap();
903
904        let tx = contract.retStruct().into_transaction_request();
905
906        let result =
907            provider.call(tx).decode_resp::<RetStruct::retStructCall>().await.unwrap().unwrap();
908
909        assert_eq!(result, RetStruct::MyStruct { a: 42, b: true });
910    }
911}