ethcontract_mock/
lib.rs

1#![deny(missing_docs, unsafe_code)]
2
3//! This crate allows emulating ethereum node with a limited number
4//! of supported RPC calls, enabling you to mock ethereum contracts.
5//!
6//! Create a new deployment using the [`Mock::deploy`] function.
7//!
8//! Configure contract's behaviour using [`Contract::expect_transaction`]
9//! and [`Contract::expect_call`].
10//!
11//! Finally, create an ethcontract's [`Instance`] by calling [`Contract::instance`],
12//! then use said instance in your tests.
13//!
14//! # Example
15//!
16//! Let's mock [voting contract] from solidity examples.
17//!
18//! First, we create a mock node and deploy a new mocked contract:
19//!
20//! ```
21//! # include!("test/doctest/common.rs");
22//! # #[tokio::main]
23//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
24//! # let abi = voting_abi();
25//! let mock = Mock::new(/* chain_id = */ 1337);
26//! let contract = mock.deploy(abi);
27//! # Ok(())
28//! # }
29//! ```
30//!
31//! Then we set up expectations for method calls:
32//!
33//! ```
34//! # include!("test/doctest/common.rs");
35//! # #[tokio::main]
36//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
37//! # let abi = voting_abi();
38//! # let account = account_for("Alice");
39//! # let mock = Mock::new(1337);
40//! # let contract = mock.deploy(abi);
41//! // We'll need to know method signatures and types.
42//! let vote: Signature<(U256,), ()> = [1, 33, 185, 63].into();
43//! let winning_proposal: Signature<(), U256> = [96, 159, 241, 189].into();
44//!
45//! // We expect some transactions calling the `vote` method.
46//! contract
47//!     .expect_transaction(vote);
48//!
49//! // We also expect calls to `winning_proposal` that will return
50//! // a value of `1`.
51//! contract
52//!     .expect_call(winning_proposal)
53//!     .returns(1.into());
54//! # Ok(())
55//! # }
56//! ```
57//!
58//! Finally, we create a dynamic instance and work with it as usual:
59//!
60//! ```
61//! # include!("test/doctest/common.rs");
62//! # #[tokio::main]
63//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
64//! # let abi = voting_abi();
65//! # let account = account_for("Alice");
66//! # let mock = Mock::new(1337);
67//! # let contract = mock.deploy(abi);
68//! # let vote: Signature<(U256,), ()> = [1, 33, 185, 63].into();
69//! # let winning_proposal: Signature<(), U256> = [96, 159, 241, 189].into();
70//! # contract.expect_transaction(vote);
71//! # contract.expect_call(winning_proposal).returns(1.into());
72//! let instance = contract.instance();
73//!
74//! instance
75//!     .method(vote, (1.into(),))?
76//!     .from(account)
77//!     .send()
78//!     .await?;
79//!
80//! let winning_proposal_index = instance
81//!     .view_method(winning_proposal, ())?
82//!     .call()
83//!     .await?;
84//! assert_eq!(winning_proposal_index, 1.into());
85//! # Ok(())
86//! # }
87//! ```
88//!
89//! # Describing expectations
90//!
91//! The mocked contracts have an interface similar to the one
92//! of the [`mockall`] crate.
93//!
94//! For each contract's method that you expect to be called during a test,
95//! call [`Contract::expect_transaction`] or [`Contract::expect_call`]
96//! and set up the created [`Expectation`] with functions such as [`returns`],
97//! [`times`], [`in_sequence`]. For greater flexibility, you can have
98//! multiple expectations attached to the same method.
99//!
100//! See [`Expectation`] for more info and examples.
101//!
102//! # Interacting with mocked contracts
103//!
104//! After contract's behaviour is programmed, you can call
105//! [`Contract::instance`] to create an ethcontract's [`Instance`].
106//!
107//! You can also get contract's address and send RPC calls directly
108//! through [`web3`].
109//!
110//! Specifically, mock node supports `eth_call`, `eth_sendRawTransaction`,
111//! and `eth_getTransactionReceipt`.
112//!
113//! At the moment, mock node can't sign transactions on its own,
114//! so `eth_sendTransaction` is not supported. Also, deploying contracts
115//! via `eth_sendRawTransaction` is not possible yet.
116//!
117//! # Mocking generated contracts
118//!
119//! Overall, generated contracts are similar to the dynamic ones:
120//! they are deployed with [`Mock::deploy`] and configured with
121//! [`Contract::expect_call`] and [`Contract::expect_transaction`].
122//!
123//! You can get generated contract's ABI using the `raw_contract` function.
124//!
125//! Generated [method signatures] are available through the `signatures`
126//! function.
127//!
128//! Finally, type-safe instance can be created using the `at` method.
129//!
130//! Here's an example of mocking an ERC20-compatible contract.
131//!
132//! First, we create a mock node and deploy a new mocked contract:
133//!
134//! ```
135//! # include!("test/doctest/common.rs");
136//! # /*
137//! ethcontract::contract!("ERC20.json");
138//! # */
139//! # ethcontract::contract!(
140//! #     "../examples/truffle/build/contracts/IERC20.json",
141//! #     contract = IERC20 as ERC20,
142//! # );
143//!
144//! # #[tokio::main]
145//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
146//! let mock = Mock::new(/* chain_id = */ 1337);
147//! let contract = mock.deploy(ERC20::raw_contract().abi.clone());
148//! # Ok(())
149//! # }
150//! ```
151//!
152//! Then we set up expectations using the generated method signatures:
153//!
154//! ```
155//! # include!("test/doctest/common.rs");
156//! # ethcontract::contract!(
157//! #     "../examples/truffle/build/contracts/IERC20.json",
158//! #     contract = IERC20 as ERC20,
159//! # );
160//! # #[tokio::main]
161//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
162//! # let account = account_for("Alice");
163//! # let recipient = address_for("Bob");
164//! # let mock = Mock::new(1337);
165//! # let contract = mock.deploy(ERC20::raw_contract().abi.clone());
166//! contract
167//!     .expect_transaction(ERC20::signatures().transfer())
168//!     .once()
169//!     .returns(true);
170//! # let instance = ERC20::at(&mock.web3(), contract.address());
171//! # instance.transfer(recipient, 100.into()).from(account).send().await?;
172//! # Ok(())
173//! # }
174//! ```
175//!
176//! Finally, we use mock contract's address to interact with the mock node:
177//!
178//! ```
179//! # include!("test/doctest/common.rs");
180//! # ethcontract::contract!(
181//! #     "../examples/truffle/build/contracts/IERC20.json",
182//! #     contract = IERC20 as ERC20,
183//! # );
184//! # #[tokio::main]
185//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
186//! # let account = account_for("Alice");
187//! # let recipient = address_for("Bob");
188//! # let mock = Mock::new(1337);
189//! # let contract = mock.deploy(ERC20::raw_contract().abi.clone());
190//! # contract.expect_transaction(ERC20::signatures().transfer());
191//! let instance = ERC20::at(&mock.web3(), contract.address());
192//! instance
193//!     .transfer(recipient, 100.into())
194//!     .from(account)
195//!     .send()
196//!     .await?;
197//! # Ok(())
198//! # }
199//! ```
200//!
201//! # Mocking gas and gas estimation
202//!
203//! Mock node allows you to customize value returned from `eth_gasPrice`
204//! RPC call. Use [`Mock::update_gas_price`] to set a new gas price.
205//!
206//! Estimating gas consumption with `eth_estimateGas` is not supported at the
207//! moment. For now, calls to `eth_estimateGas` always return `1`.
208//!
209//! [`web3-rs`]: ethcontract::web3
210//! [`web3`]: ethcontract::web3
211//! [`expect_call`]: Contract::expect_call
212//! [`expect_transaction`]: Contract::expect_transaction
213//! [`returns`]: Expectation::returns
214//! [`times`]: Expectation::times
215//! [`in_sequence`]: Expectation::in_sequence
216//! [`Instance`]: ethcontract::Instance
217//! [voting contract]: https://docs.soliditylang.org/en/v0.8.6/solidity-by-example.html#voting
218//! [method signatures]: Signature
219
220use crate::predicate::TuplePredicate;
221use crate::range::TimesRange;
222use ethcontract::common::hash::H32;
223use ethcontract::common::Abi;
224use ethcontract::dyns::{DynInstance, DynTransport, DynWeb3};
225use ethcontract::tokens::Tokenize;
226use ethcontract::{Address, U256};
227use std::marker::PhantomData;
228use std::sync::Arc;
229
230#[doc(no_inline)]
231pub use ethcontract::contract::Signature;
232
233mod details;
234mod predicate;
235mod range;
236pub mod utils;
237
238#[cfg(test)]
239mod test;
240
241/// Mock ethereum node.
242///
243/// This struct implements a virtual ethereum node with a limited number
244/// of supported RPC calls. You can interact with it via the standard
245/// transport from `web3`.
246///
247/// The main feature of this struct is deploying mocked contracts
248/// and interacting with them. Create new mocked contract with a call
249/// to [`deploy`] function. Then use the returned struct to set up
250/// expectations on contract methods, get deployed contract's address
251/// and [`Instance`] and make actual calls to it.
252///
253/// Deploying contracts with an RPC call is not supported at the moment.
254///
255/// [`deploy`]: Mock::deploy
256/// [`Instance`]: ethcontract::Instance
257#[derive(Clone)]
258pub struct Mock {
259    transport: details::MockTransport,
260}
261
262impl Mock {
263    /// Creates a new mock chain.
264    pub fn new(chain_id: u64) -> Self {
265        Mock {
266            transport: details::MockTransport::new(chain_id),
267        }
268    }
269
270    /// Creates a `Web3` object that can be used to interact with
271    /// the mocked chain.
272    pub fn web3(&self) -> DynWeb3 {
273        DynWeb3::new(self.transport())
274    }
275
276    /// Creates a `Transport` object that can be used to interact with
277    /// the mocked chain.
278    pub fn transport(&self) -> DynTransport {
279        DynTransport::new(self.transport.clone())
280    }
281
282    /// Deploys a new mocked contract and returns an object that allows
283    /// configuring expectations for contract methods.
284    pub fn deploy(&self, abi: Abi) -> Contract {
285        let address = self.transport.deploy(&abi);
286        Contract {
287            transport: self.transport.clone(),
288            address,
289            abi,
290        }
291    }
292
293    /// Deploys a new mocked contract with specified address and returns an object that allows
294    /// configuring expectations for contract methods.
295    pub fn deploy_with_address(&self, abi: Abi, address: Address) -> Contract {
296        self.transport.deploy_with_address(&abi, address);
297        Contract {
298            transport: self.transport.clone(),
299            address,
300            abi,
301        }
302    }
303
304    /// Updates gas price that is returned by RPC call `eth_gasPrice`.
305    ///
306    /// Mock node does not simulate gas consumption, so this value does not
307    /// affect anything if you don't call `eth_gasPrice`.
308    pub fn update_gas_price(&self, gas_price: u64) {
309        self.transport.update_gas_price(gas_price);
310    }
311
312    /// Verifies that all expectations on all contracts have been met,
313    /// then clears all expectations.
314    ///
315    /// Sometimes its useful to validate all expectations mid-test,
316    /// throw them away, and add new ones. That’s what checkpoints do.
317    /// See [mockall documentation] for more info.
318    ///
319    /// Note that all expectations returned from [`Contract::expect`] method
320    /// become invalid after checkpoint. Modifying them will result in panic.
321    ///
322    /// [mockall documentation]: https://docs.rs/mockall/#checkpoints
323    pub fn checkpoint(&self) {
324        self.transport.checkpoint();
325    }
326}
327
328impl std::fmt::Debug for Mock {
329    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330        f.write_str("Mock")
331    }
332}
333
334/// A mocked contract deployed by the mock node.
335///
336/// This struct allows setting up expectations on which contract methods
337/// will be called, with what arguments, in what order, etc.
338pub struct Contract {
339    transport: details::MockTransport,
340    address: Address,
341    abi: Abi,
342}
343
344impl Contract {
345    /// Creates a `Web3` object that can be used to interact with
346    /// the mocked chain on which this contract is deployed.
347    pub fn web3(&self) -> DynWeb3 {
348        DynWeb3::new(self.transport())
349    }
350
351    /// Creates a `Transport` object that can be used to interact with
352    /// the mocked chain.
353    pub fn transport(&self) -> DynTransport {
354        DynTransport::new(self.transport.clone())
355    }
356
357    /// Creates a contract `Instance` that can be used to interact with
358    /// this contract.
359    pub fn instance(&self) -> DynInstance {
360        DynInstance::at(self.web3(), Arc::new(self.abi.clone().into()), self.address)
361    }
362
363    /// Consumes this object and transforms it into a contract `Instance`
364    /// that can be used to interact with this contract.
365    pub fn into_instance(self) -> DynInstance {
366        DynInstance::at(self.web3(), Arc::new(self.abi.into()), self.address)
367    }
368
369    /// Returns a reference to the contract's ABI.
370    pub fn abi(&self) -> &Abi {
371        &self.abi
372    }
373
374    /// Returns contract's address.
375    pub fn address(&self) -> Address {
376        self.address
377    }
378
379    /// Adds a new expectation for contract method. See [`Expectation`].
380    ///
381    /// Generic parameters are used to specify which rust types should be used
382    /// to encode and decode method's arguments and return value. If you're
383    /// using generated contracts, they will be inferred automatically.
384    /// If not, you may have to specify them manually.
385    ///
386    /// # Notes
387    ///
388    /// Expectations generated by this method will allow both view calls
389    /// and transactions. This is usually undesired, so prefer using
390    /// [`expect_call`] and [`expect_transaction`] instead.
391    ///
392    /// [`expect_call`]: Contract::expect_call
393    /// [`expect_transaction`]: Contract::expect_transaction
394    pub fn expect<P: Tokenize + Send + 'static, R: Tokenize + Send + 'static>(
395        &self,
396        signature: impl Into<Signature<P, R>>,
397    ) -> Expectation<P, R> {
398        let signature = signature.into().into_inner();
399        let (index, generation) = self.transport.expect::<P, R>(self.address, signature);
400        Expectation {
401            transport: self.transport.clone(),
402            address: self.address,
403            signature,
404            index,
405            generation,
406            _ph: PhantomData,
407        }
408    }
409
410    /// Adds a new expectation for contract method that only matches view calls.
411    ///
412    /// This is an equivalent of [`expect`] followed by [`allow_transactions`]`(false)`.
413    ///
414    /// [`expect`]: Contract::expect
415    /// [`allow_transactions`]: Expectation::allow_transactions
416    pub fn expect_call<P: Tokenize + Send + 'static, R: Tokenize + Send + 'static>(
417        &self,
418        signature: impl Into<Signature<P, R>>,
419    ) -> Expectation<P, R> {
420        self.expect(signature).allow_transactions(false)
421    }
422
423    /// Adds a new expectation for contract method that only matches transactions.
424    ///
425    /// This is an equivalent of [`expect`] followed by [`allow_calls`]`(false)`.
426    ///
427    /// [`expect`]: Contract::expect
428    /// [`allow_calls`]: Expectation::allow_calls
429    pub fn expect_transaction<P: Tokenize + Send + 'static, R: Tokenize + Send + 'static>(
430        &self,
431        signature: impl Into<Signature<P, R>>,
432    ) -> Expectation<P, R> {
433        self.expect(signature).allow_calls(false)
434    }
435
436    /// Verifies that all expectations on this contract have been met,
437    /// then clears all expectations.
438    ///
439    /// Sometimes its useful to validate all expectations mid-test,
440    /// throw them away, and add new ones. That’s what checkpoints do.
441    /// See [mockall documentation] for more info.
442    ///
443    /// Note that all expectations returned from [`expect`] method
444    /// become invalid after checkpoint. Modifying them will result in panic.
445    ///
446    /// [mockall documentation]: https://docs.rs/mockall/#checkpoints
447    /// [`expect`]: Contract::expect
448    pub fn checkpoint(&self) {
449        self.transport.contract_checkpoint(self.address);
450    }
451}
452
453/// Expectation for contract method.
454///
455/// A method could have multiple expectations associated with it.
456/// Each expectation specifies how the method should be called, how many times,
457/// with what arguments, etc.
458///
459/// When a method gets called, mock node determines if the call is expected
460/// or not. It goes through each of the method's expectations in order they
461/// were created, searching for the first expectation that matches the call.
462///
463/// If a suitable expectation is found, it is used to determine method's
464/// return value and other transaction properties. If not, the call
465/// is considered unexpected, and mock node panics.
466///
467/// To determine if a particular expectation should be used for the given call,
468/// mock node uses two of the expectation's properties:
469///
470/// - [`predicate`] checks if method's arguments and transaction properties
471///   match a certain criteria;
472/// - [times limiter] is used to limit number of times a single expectation
473///   can be used.
474///
475/// To determine result of a method call, [`returns`] property is used.
476///
477/// # Notes
478///
479/// Expectations can't be changed after they were used. That is, if you try
480/// to modify an expectation after making any calls to its contract method,
481/// mock node will panic. This happens because modifying an already-used
482/// expectation may break node's internal state. Adding new expectations
483/// at any time is fine, though.
484///
485/// [`predicate`]: Expectation::predicate
486/// [times limiter]: Expectation::times
487/// [`returns`]: Expectation::returns
488pub struct Expectation<P: Tokenize + Send + 'static, R: Tokenize + Send + 'static> {
489    transport: details::MockTransport,
490    address: Address,
491    signature: H32,
492    index: usize,
493    generation: usize,
494    _ph: PhantomData<(P, R)>,
495}
496
497// Allow not requiring `must_use` as `Expectation`s have side effects, but
498// return `Self` as a convenience for chaining operations. Note that this lint
499// is on nighlty only, so we also need to allow `unknown_lints` here to silence
500// warnings on all Rust versions we build for.
501#[allow(unknown_lints)]
502#[allow(clippy::return_self_not_must_use)]
503impl<P: Tokenize + Send + 'static, R: Tokenize + Send + 'static> Expectation<P, R> {
504    /// Specifies how many times this expectation can be called.
505    ///
506    /// By default, each expectation can be called any number of times,
507    /// including zero. This method allows specifying a more precise range.
508    ///
509    /// For example, use `times(1)` to indicate that the expectation
510    /// should be called exactly [`once`]. Or use `times(1..)` to indicate
511    /// that it should be called at least once. Any range syntax is accepted.
512    ///
513    /// If the expectation gets called less that the specified number
514    /// of times, the test panics.
515    ///
516    /// If it gets called enough number of times, expectation is considered
517    /// satisfied. It becomes inactive and is no longer checked when processing
518    /// new method calls.
519    ///
520    /// # Examples
521    ///
522    /// Consider a method with two expectations:
523    ///
524    /// ```
525    /// # include!("test/doctest/common.rs");
526    /// # #[tokio::main]
527    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
528    /// # let contract = contract();
529    /// # let signature = signature();
530    /// contract
531    ///     .expect_call(signature)
532    ///     .times(1..=2);
533    /// contract
534    ///     .expect_call(signature);
535    /// # contract.instance().view_method(signature, (0, 0))?.call().await?;
536    /// # Ok(())
537    /// # }
538    /// ```
539    ///
540    /// The first two calls to this method will be dispatched to the first
541    /// expectation. Then first expectation will become satisfied, and all
542    /// other calls will be dispatched to the second one.
543    ///
544    /// # Notes
545    ///
546    /// When expectation becomes satisfied, previous expectations
547    /// are not altered and may still be unsatisfied. This is important
548    /// when you have expectations with predicates:
549    ///
550    /// ```
551    /// # include!("test/doctest/common.rs");
552    /// # #[tokio::main]
553    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
554    /// # let contract = contract();
555    /// # let signature = signature();
556    /// contract
557    ///     .expect_call(signature)
558    ///     .predicate_fn(|(a, b)| a == b)
559    ///     .times(1..=2);
560    /// contract
561    ///     .expect_call(signature)
562    ///     .times(1);
563    /// contract
564    ///     .expect_call(signature)
565    ///     .times(..);
566    /// # contract.instance().view_method(signature, (0, 0))?.call().await?;
567    /// # contract.instance().view_method(signature, (0, 1))?.call().await?;
568    /// # Ok(())
569    /// # }
570    /// ```
571    ///
572    /// Here, first expectation can be called one or two times, second
573    /// expectation can be called exactly once, and third expectation
574    /// can be called arbitrary number of times.
575    ///
576    /// Now, consider the following sequence of calls:
577    ///
578    /// ```
579    /// # include!("test/doctest/common.rs");
580    /// # #[tokio::main]
581    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
582    /// # let contract = contract();
583    /// # let signature = signature();
584    /// # let instance = contract.instance();
585    /// # contract.expect(signature);
586    /// instance
587    ///     .method(signature, (1, 1))?
588    ///     .call()
589    ///     .await?;
590    /// instance
591    ///     .method(signature, (2, 3))?
592    ///     .call()
593    ///     .await?;
594    /// instance
595    ///     .method(signature, (5, 5))?
596    ///     .call()
597    ///     .await?;
598    /// # Ok(())
599    /// # }
600    /// ```
601    ///
602    /// First call gets dispatched to the first expectation. Second call
603    /// can't be dispatched to the first expectation because of its predicate,
604    /// so it gets dispatched to the second one. Now, one may assume that
605    /// the third call will be dispatched to the third expectation. However,
606    /// first expectation can be called one more time, so it is not satisfied
607    /// yet. Because of this, third call gets dispatched
608    /// to the first expectation.
609    ///
610    /// [`once`]: Expectation::once
611    pub fn times(self, times: impl Into<TimesRange>) -> Self {
612        self.transport.times::<P, R>(
613            self.address,
614            self.signature,
615            self.index,
616            self.generation,
617            times.into(),
618        );
619        self
620    }
621
622    /// Indicates that this expectation can be called exactly zero times.
623    ///
624    /// See [`times`] for more info.
625    ///
626    /// [`times`]: Expectation::times
627    pub fn never(self) -> Self {
628        self.times(0)
629    }
630
631    /// Indicates that this expectation can be called exactly one time.
632    ///
633    /// See [`times`] for more info.
634    ///
635    /// [`times`]: Expectation::times
636    pub fn once(self) -> Self {
637        self.times(1)
638    }
639
640    /// Adds this expectation to a sequence.
641    ///
642    /// By default, expectations may be matched in any order. If a stricter
643    /// order is required, you can use sequences. See [mockall documentation]
644    /// for more info.
645    ///
646    /// # Limitations
647    ///
648    /// An expectation can be in one sequence only.
649    ///
650    /// Also, an expectation should have [`times`] limit set to an exact
651    /// number of calls, i.e., [`once`], two times, and so on.
652    ///
653    /// [mockall documentation]: https://docs.rs/mockall/#sequences
654    /// [`times`]: Expectation::times
655    /// [`once`]: Expectation::once
656    pub fn in_sequence(self, sequence: &mut mockall::Sequence) -> Self {
657        self.transport.in_sequence::<P, R>(
658            self.address,
659            self.signature,
660            self.index,
661            self.generation,
662            sequence,
663        );
664        self
665    }
666
667    /// Sets number of blocks that should be mined on top of the transaction
668    /// block. This method can be useful when there are custom transaction
669    /// confirmation settings.
670    pub fn confirmations(self, confirmations: u64) -> Self {
671        self.transport.confirmations::<P, R>(
672            self.address,
673            self.signature,
674            self.index,
675            self.generation,
676            confirmations,
677        );
678        self
679    }
680
681    /// Sets predicate for this expectation.
682    ///
683    /// If method has multiple expectations, they are checked one-by-one,
684    /// in order they were created. First expectation with a predicate that
685    /// matches method's parameters is called.
686    ///
687    /// This method accepts a tuple of predicates, one predicate
688    /// for each parameter.
689    ///
690    /// This method will overwrite any predicate that was set before.
691    ///
692    /// # Examples
693    ///
694    /// ```
695    /// # include!("test/doctest/common.rs");
696    /// # #[tokio::main]
697    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
698    /// # let contract = contract();
699    /// # let signature = signature();
700    /// contract
701    ///     .expect_call(signature)
702    ///     .predicate((predicate::eq(1), predicate::eq(1)))
703    ///     .returns(1);
704    /// contract
705    ///     .expect_call(signature)
706    ///     .predicate_fn(|(a, b)| a > b)
707    ///     .returns(2);
708    /// contract
709    ///     .expect_call(signature)
710    ///     .returns(3);
711    /// # Ok(())
712    /// # }
713    /// ```
714    ///
715    /// Here, we have three expectations, resulting in the following behaviour.
716    /// If both arguments are equal to `1`, method returns `1`.
717    /// Otherwise, if the first argument is greater than the second one, method
718    /// returns `2`. Otherwise, it returns `3`.
719    ///
720    /// # Notes
721    ///
722    /// Having multiple predicates shines for complex setups that involve
723    /// [call sequences] and [limiting number of expectation uses].
724    /// For simpler setups like the one above, [`returns_fn`] may be more
725    /// clear and concise, and also more efficient.
726    ///
727    /// [call sequences]: Expectation::in_sequence
728    /// [limiting number of expectation uses]: Expectation::times
729    /// [`returns_fn`]: Expectation::returns_fn
730    pub fn predicate<T>(self, pred: T) -> Self
731    where
732        T: TuplePredicate<P> + Send + 'static,
733        <T as predicate::TuplePredicate<P>>::P: Send,
734    {
735        self.transport.predicate::<P, R>(
736            self.address,
737            self.signature,
738            self.index,
739            self.generation,
740            Box::new(pred.into_predicate()),
741        );
742        self
743    }
744
745    /// Sets predicate function for this expectation. This function accepts
746    /// a tuple of method's arguments and returns `true` if this
747    /// expectation should be called. See [`predicate`] for more info.
748    ///
749    /// This method will overwrite any predicate that was set before.
750    ///
751    /// [`predicate`]: Expectation::predicate
752    pub fn predicate_fn(self, pred: impl Fn(&P) -> bool + Send + 'static) -> Self {
753        self.transport.predicate_fn::<P, R>(
754            self.address,
755            self.signature,
756            self.index,
757            self.generation,
758            Box::new(pred),
759        );
760        self
761    }
762
763    /// Sets predicate function for this expectation. This function accepts
764    /// a [call context] and a tuple of method's arguments and returns `true`
765    /// if this expectation should be called. See [`predicate`] for more info.
766    ///
767    /// This method will overwrite any predicate that was set before.
768    ///
769    /// [call context]: CallContext
770    /// [`predicate`]: Expectation::predicate
771    pub fn predicate_fn_ctx(
772        self,
773        pred: impl Fn(&CallContext, &P) -> bool + Send + 'static,
774    ) -> Self {
775        self.transport.predicate_fn_ctx::<P, R>(
776            self.address,
777            self.signature,
778            self.index,
779            self.generation,
780            Box::new(pred),
781        );
782        self
783    }
784
785    /// Indicates that this expectation only applies to view calls.
786    ///
787    /// This method will not override predicates set by [`predicate`] and
788    /// similar methods.
789    ///
790    /// See also [`Contract::expect_call`].
791    ///
792    /// [`predicate`]: Expectation::predicate
793    pub fn allow_calls(self, allow_calls: bool) -> Self {
794        self.transport.allow_calls::<P, R>(
795            self.address,
796            self.signature,
797            self.index,
798            self.generation,
799            allow_calls,
800        );
801        self
802    }
803
804    /// Indicates that this expectation only applies to transactions.
805    ///
806    /// This method will not override predicates set by [`predicate`] and
807    /// similar methods.
808    ///
809    /// See also [`Contract::expect_transaction`].
810    ///
811    /// [`predicate`]: Expectation::predicate
812    pub fn allow_transactions(self, allow_transactions: bool) -> Self {
813        self.transport.allow_transactions::<P, R>(
814            self.address,
815            self.signature,
816            self.index,
817            self.generation,
818            allow_transactions,
819        );
820        self
821    }
822
823    /// Sets return value of the method.
824    ///
825    /// By default, call to this expectation will result in solidity's default
826    /// value for the method's return type. This method allows specifying
827    /// a custom return value.
828    ///
829    /// This method will overwrite any return value or callback
830    /// that was set before.
831    pub fn returns(self, returns: R) -> Self {
832        self.transport.returns::<P, R>(
833            self.address,
834            self.signature,
835            self.index,
836            self.generation,
837            returns,
838        );
839        self
840    }
841
842    /// Sets callback function that will be used to calculate return value
843    /// of the method. This function accepts a tuple of method's arguments
844    /// and returns method's result or [`Err`] if transaction
845    /// should be reverted.
846    ///
847    /// A callback set by this method will be called even if its return value
848    /// is unused, such as when processing a transaction. This means that
849    /// callback can be used to further check method's parameters, perform
850    /// asserts and invoke other logic.
851    ///
852    /// This method will overwrite any return value or callback
853    /// that was set before.
854    ///
855    /// See [`returns`] for more info.
856    ///
857    /// [`returns`]: Expectation::returns
858    pub fn returns_fn(self, returns: impl Fn(P) -> Result<R, String> + Send + 'static) -> Self {
859        self.transport.returns_fn::<P, R>(
860            self.address,
861            self.signature,
862            self.index,
863            self.generation,
864            Box::new(returns),
865        );
866        self
867    }
868
869    /// Sets callback function that will be used to calculate return value
870    /// of the method. This function accepts a [call context] and a tuple
871    /// of method's arguments and returns method's result or [`Err`]
872    /// if transaction should be reverted.
873    ///
874    /// A callback set by this method will be called even if its return value
875    /// is unused, such as when processing a transaction. This means that
876    /// callback can be used to further check method's parameters, perform
877    /// asserts and invoke other logic.
878    ///
879    /// This method will overwrite any return value or callback
880    /// that was set before.
881    ///
882    /// See [`returns`] for more info.
883    ///
884    /// [call context]: CallContext
885    /// [`returns`]: Expectation::returns
886    pub fn returns_fn_ctx(
887        self,
888        returns: impl Fn(&CallContext, P) -> Result<R, String> + Send + 'static,
889    ) -> Self {
890        self.transport.returns_fn_ctx::<P, R>(
891            self.address,
892            self.signature,
893            self.index,
894            self.generation,
895            Box::new(returns),
896        );
897        self
898    }
899
900    /// Sets return value of the method to an error, meaning that calls to this
901    /// expectation result in reverted transaction.
902    ///
903    /// This method will overwrite any return value or callback
904    /// that was set before.
905    ///
906    /// See [`returns`] for more info.
907    ///
908    /// [`returns`]: Expectation::returns
909    pub fn returns_error(self, error: String) -> Self {
910        self.transport.returns_error::<P, R>(
911            self.address,
912            self.signature,
913            self.index,
914            self.generation,
915            error,
916        );
917        self
918    }
919
920    /// Sets return value of the method to a default value for its solidity type.
921    /// See [`returns`] for more info.
922    ///
923    /// This method will overwrite any return value or callback
924    /// that was set before.
925    ///
926    /// Note that this method doesn't use [`Default`] trait for `R`. Instead,
927    /// it constructs default value according to solidity rules.
928    ///
929    /// [`returns`]: Expectation::returns
930    pub fn returns_default(self) -> Self {
931        self.transport.returns_default::<P, R>(
932            self.address,
933            self.signature,
934            self.index,
935            self.generation,
936        );
937        self
938    }
939}
940
941/// Information about method call that's being processed.
942pub struct CallContext {
943    /// If `true`, this is a view call, otherwise this is a transaction.
944    pub is_view_call: bool,
945
946    /// Account that issued a view call or a transaction.
947    ///
948    /// Can be zero in case of a view call.
949    pub from: Address,
950
951    /// Address of the current contract.
952    pub to: Address,
953
954    /// Current nonce of the account that issued a view call or a transaction.
955    pub nonce: U256,
956
957    /// Maximum gas amount that this operation is allowed to spend.
958    ///
959    /// Mock node does not simulate gas consumption, so this value does not
960    /// affect anything if you don't check it in your test code.
961    pub gas: U256,
962
963    /// Gas price for this view call or transaction.
964    ///
965    /// Mock node does not simulate gas consumption, so this value does not
966    /// affect anything if you don't check it in your test code.
967    pub gas_price: U256,
968
969    /// Amount of ETH that's transferred with the call.
970    ///
971    /// This value is only non-zero if the method is payable.
972    pub value: U256,
973}