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