[][src]Struct ethers_contract::Multicall

pub struct Multicall<M> { /* fields omitted */ }

A Multicall is an abstraction for sending batched calls/transactions to the Ethereum blockchain. It stores an instance of the Multicall smart contract and the user provided list of transactions to be made.

Multicall can instantiate the Multicall contract instance from the chain ID of the client supplied to new. It supports the Ethereum mainnet, as well as testnets Rinkeby, Goerli and Kovan.

Additionally, the block number can be provided for the call by using the block method. Build on the Multicall instance by adding calls using the add_call method.

Example

use ethers::{
    abi::Abi,
    contract::{Contract, Multicall},
    providers::{Middleware, Http, Provider, PendingTransaction},
    types::{Address, H256, U256},
};
use std::{convert::TryFrom, sync::Arc};

// this is a dummy address used for illustration purpose
let address = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee".parse::<Address>()?;

// (ugly way to write the ABI inline, you can otherwise read it from a file)
let abi: Abi = serde_json::from_str(r#"[{"inputs":[{"internalType":"string","name":"value","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"author","type":"address"},{"indexed":true,"internalType":"address","name":"oldAuthor","type":"address"},{"indexed":false,"internalType":"string","name":"oldValue","type":"string"},{"indexed":false,"internalType":"string","name":"newValue","type":"string"}],"name":"ValueChanged","type":"event"},{"inputs":[],"name":"getValue","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"value","type":"string"}],"name":"setValue","outputs":[],"stateMutability":"nonpayable","type":"function"}]"#)?;

// connect to the network
let client = Provider::<Http>::try_from("https://kovan.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27")?;

// create the contract object. This will be used to construct the calls for multicall
let client = Arc::new(client);
let contract = Contract::<Provider<Http>>::new(address, abi, Arc::clone(&client));

// note that these [`ContractCall`]s are futures, and need to be `.await`ed to resolve.
// But we will let `Multicall` to take care of that for us
let first_call = contract.method::<_, String>("getValue", ())?;
let second_call = contract.method::<_, Address>("lastSender", ())?;

// since this example connects to the Kovan testnet, we need not provide an address for
// the Multicall contract and we set that to `None`. If you wish to provide the address
// for the Multicall contract, you can pass the `Some(multicall_addr)` argument.
// Construction of the `Multicall` instance follows the builder pattern
let mut multicall = Multicall::new(Arc::clone(&client), None).await?;
multicall
    .add_call(first_call)
    .add_call(second_call);

// `await`ing on the `call` method lets us fetch the return values of both the above calls
// in one single RPC call
let _return_data: (String, Address) = multicall.call().await?;

// the same `Multicall` instance can be re-used to do a different batch of transactions.
// Say we wish to broadcast (send) a couple of transactions via the Multicall contract.
let first_broadcast = contract.method::<_, H256>("setValue", "some value".to_owned())?;
let second_broadcast = contract.method::<_, H256>("setValue", "new value".to_owned())?;
let multicall = multicall
    .clear_calls()
    .add_call(first_broadcast)
    .add_call(second_broadcast);

// `await`ing the `send` method waits for the transaction to be broadcast, which also
// returns the transaction hash
let tx_hash = multicall.send().await?;
let _tx_receipt = PendingTransaction::new(tx_hash, &client).await?;

// you can also query ETH balances of multiple addresses
let address_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".parse::<Address>()?;
let address_2 = "ffffffffffffffffffffffffffffffffffffffff".parse::<Address>()?;
let multicall = multicall
    .clear_calls()
    .eth_balance_of(address_1)
    .eth_balance_of(address_2);
let _balances: (U256, U256) = multicall.call().await?;

Implementations

impl<M: Middleware> Multicall<M>[src]

pub async fn new<C: Into<Arc<M>>>(
    client: C,
    address: Option<Address>
) -> Result<Self, ContractError<M>>
[src]

Creates a new Multicall instance from the provided client. If provided with an address, it instantiates the Multicall contract with that address. Otherwise it fetches the address from the address book.

Panics

If a None address is provided, and the provided client also does not belong to one of the supported network IDs (mainnet, kovan, rinkeby and goerli)

pub fn block<T: Into<BlockNumber>>(mut self: Self, block: T) -> Self[src]

Sets the block field for the multicall aggregate call

pub fn add_call<D: Detokenize>(&mut self, call: ContractCall<M, D>) -> &mut Self[src]

Appends a call to the list of calls for the Multicall instance

Panics

If more than the maximum number of supported calls are added. The maximum limits is constrained due to tokenization/detokenization support for tuples

pub fn eth_balance_of(&mut self, addr: Address) -> &mut Self[src]

Appends a call to the list of calls for the Multicall instance for querying the ETH balance of an address

Panics

If more than the maximum number of supported calls are added. The maximum limits is constrained due to tokenization/detokenization support for tuples

pub fn clear_calls(&mut self) -> &mut Self[src]

Clear the batch of calls from the Multicall instance. Re-use the already instantiated Multicall, to send a different batch of transactions or do another aggregate query

let mut multicall = Multicall::new(client, None).await?;
multicall
    .add_call(broadcast_1)
    .add_call(broadcast_2);

let _tx_hash = multicall.send().await?;

multicall
    .clear_calls()
    .add_call(call_1)
    .add_call(call_2);
let return_data: (String, Address) = multicall.call().await?;

pub async fn call<D: Detokenize>(&self) -> Result<D, ContractError<M>>[src]

Queries the Ethereum blockchain via an eth_call, but via the Multicall contract.

It returns a ContractError<M> if there is any error in the RPC call or while detokenizing the tokens back to the expected return type. The return type must be annonated while calling this method.

// If the Solidity function calls has the following return types:
// 1. `returns (uint256)`
// 2. `returns (string, address)`
// 3. `returns (bool)`
let result: (U256, (String, Address), bool) = multicall.call().await?;

Note: this method does not send a transaction from your account

pub async fn send(&self) -> Result<TxHash, ContractError<M>>[src]

Signs and broadcasts a batch of transactions by using the Multicall contract as proxy.

let tx_hash = multicall.send().await?;

Note: this method sends a transaction from your account, and will return an error if you do not have sufficient funds to pay for gas

Trait Implementations

impl<M: Clone> Clone for Multicall<M>[src]

Auto Trait Implementations

impl<M> RefUnwindSafe for Multicall<M> where
    M: RefUnwindSafe
[src]

impl<M> Send for Multicall<M> where
    M: Send + Sync
[src]

impl<M> Sync for Multicall<M> where
    M: Send + Sync
[src]

impl<M> Unpin for Multicall<M>[src]

impl<M> UnwindSafe for Multicall<M> where
    M: RefUnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Conv for T

impl<T> FmtForward for T

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pipe for T

impl<T> PipeAsRef for T

impl<T> PipeBorrow for T

impl<T> PipeDeref for T

impl<T> PipeRef for T

impl<T> Same<T> for T

type Output = T

Should always be Self

impl<T> Tap for T

impl<T, U> TapAsRef<U> for T where
    U: ?Sized

impl<T, U> TapBorrow<U> for T where
    U: ?Sized

impl<T> TapDeref for T

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T> TryConv for T

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,