pub struct ContractInstance<B, M> { /* private fields */ }
Available on crate feature providers only.
Expand description

A Contract is an abstraction of an executable program on the Ethereum Blockchain. It has code (called byte code) as well as allocated long-term memory (called storage). Every deployed Contract has an address, which is used to connect to it so that it may be sent messages to call its methods.

A Contract can emit Events, which can be efficiently observed by applications to be notified when a contract has performed specific operation.

There are two types of methods that can be called on a Contract:

  1. A Constant method may not add, remove or change any data in the storage, nor log any events, and may only call Constant methods on other contracts. These methods are free (no Ether is required) to call. The result from them may also be returned to the caller. Constant methods are marked as pure and view in Solidity.

  2. A Non-Constant method requires a fee (in Ether) to be paid, but may perform any state-changing operation desired, log events, send ether and call Non-Constant methods on other Contracts. These methods cannot return their result to the caller. These methods must be triggered by a transaction, sent by an Externally Owned Account (EOA) either directly or indirectly (i.e. called from another contract), and are required to be mined before the effects are present. Therefore, the duration required for these operations can vary widely, and depend on the transaction gas price, network congestion and miner priority heuristics.

The Contract API provides simple way to connect to a Contract and call its methods, as functions on a Rust struct, handling all the binary protocol conversion, internal name mangling and topic construction. This allows a Contract object to be used like any standard Rust struct, without having to worry about the low-level details of the Ethereum Virtual Machine or Blockchain.

The Contract definition (called an Application Binary Interface, or ABI) must be provided to instantiate a contract and the available methods and events will be made available to call by providing their name as a str via the method and event methods. If non-existing names are given, the function/event call will fail.

Alternatively, you can and should use the abigen macro, or the Abigen builder to generate type-safe bindings to your contracts.

§Example

Assuming we already have our contract deployed at address, we’ll proceed to interact with its methods and retrieve raw logs it has emitted.

use ethers_core::{
    abi::Abi,
    types::{Address, H256},
};
use ethers_contract::Contract;
use ethers_providers::{Provider, Http};
use std::{convert::TryFrom, sync::Arc};

// this is a fake address used just for this example
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("http://localhost:8545").unwrap();

// create the contract object at the address
let contract = Contract::new(address, abi, Arc::new(client));

// Calling constant methods is done by calling `call()` on the method builder.
// (if the function takes no arguments, then you must use `()` as the argument)
let init_value: String = contract
    .method::<_, String>("getValue", ())?
    .call()
    .await?;

// Non-constant methods are executed via the `send()` call on the method builder.
let call = contract
    .method::<_, H256>("setValue", "hi".to_owned())?;
let pending_tx = call.send().await?;

// `await`ing on the pending transaction resolves to a transaction receipt
let receipt = pending_tx.confirmations(6).await?;

§Event Logging

Querying structured logs requires you to have defined a struct with the expected datatypes and to have implemented Detokenize for it. This boilerplate code is generated for you via the abigen and Abigen builder utilities.

use ethers_core::{abi::Abi, types::Address};
use ethers_contract::{Contract, EthEvent};
use ethers_providers::{Provider, Http, Middleware};
use std::{convert::TryFrom, sync::Arc};
use ethers_core::abi::{Detokenize, Token, InvalidOutputType};

#[derive(Clone, Debug, EthEvent)]
struct ValueChanged {
    old_author: Address,
    new_author: Address,
    old_value: String,
    new_value: String,
}

let logs: Vec<ValueChanged> = contract
    .event()
    .from_block(0u64)
    .query()
    .await?;

println!("{:?}", logs);

Disclaimer: these above docs have been adapted from the corresponding ethers.js page

§Usage Note

ContractInternal accepts any client that implements B: Borrow<M> where M :Middleware. Previous Contract versions used only arcs, and relied heavily on Arc. Due to constraints on the FunctionCall type, calling contracts requires a B: Borrow<M> + Clone. This is fine for most middlware. However, when B is an owned middleware that is not Clone, we cannot issue contract calls. Some notable exceptions:

  • NonceManagerMiddleware
  • SignerMiddleware (when using a non-Clone Signer)

When using non-Clone middlewares, instead of instantiating a contract that OWNS the middlware, pass the contract a REFERENCE to the middleware. This will fix the trait bounds issue (as &M is always Clone).

We expect to fix this fully in a future version

Implementations§

source§

impl<B, M> ContractInstance<B, M>
where B: Borrow<M>,

source

pub fn address(&self) -> Address

Returns the contract’s address

source

pub fn abi(&self) -> &Abi

Returns a reference to the contract’s ABI.

source

pub fn client(&self) -> B
where B: Clone,

Returns a pointer to the contract’s client.

source

pub fn client_ref(&self) -> &M

Returns a reference to the contract’s client.

source§

impl<B, M> ContractInstance<B, M>
where B: Borrow<M>, M: Middleware,

source

pub fn event_of_type<D: EthEvent>(client: B) -> Event<B, M, D>

Returns an Event builder for the provided event.

This function operates in a static context, then it does not require a self to reference to instantiate an Event builder.

source§

impl<B, M> ContractInstance<B, M>
where B: Borrow<M>, M: Middleware,

source

pub fn new( address: impl Into<Address>, abi: impl Into<BaseContract>, client: B ) -> Self

Creates a new contract from the provided client, abi and address

source

pub fn connect<N>(&self, client: Arc<N>) -> ContractInstance<Arc<N>, N>
where N: Middleware,

Returns a new contract instance using the provided client

Clones self internally

source

pub fn connect_with<C, N>(&self, client: C) -> ContractInstance<C, N>
where C: Borrow<N>,

Returns a new contract instance using the provided client

Clones self internally

source§

impl<B, M> ContractInstance<B, M>
where B: Clone + Borrow<M>, M: Middleware,

source

pub fn event_with_filter<D>(&self, filter: Filter) -> Event<B, M, D>

Returns an Event builder with the provided filter.

source

pub fn event<D: EthEvent>(&self) -> Event<B, M, D>

Returns an Event builder for the provided event.

source

pub fn event_for_name<D>(&self, name: &str) -> Result<Event<B, M, D>, Error>

Returns an Event builder with the provided name.

source

pub fn method_hash<T: Tokenize, D: Detokenize>( &self, signature: Selector, args: T ) -> Result<FunctionCall<B, M, D>, AbiError>

Returns a transaction builder for the selected function signature. This should be preferred if there are overloaded functions in your smart contract

source

pub fn method<T: Tokenize, D: Detokenize>( &self, name: &str, args: T ) -> Result<FunctionCall<B, M, D>, AbiError>

Returns a transaction builder for the provided function name. If there are multiple functions with the same name due to overloading, consider using the method_hash method instead, since this will use the first match.

source

pub fn at<T: Into<Address>>(&self, address: T) -> Self

Returns a new contract instance at address.

Clones self internally

Methods from Deref<Target = BaseContract>§

source

pub fn encode<T: Tokenize>( &self, name: &str, args: T ) -> Result<Bytes, AbiError>

Returns the ABI encoded data for the provided function and arguments

If the function exists multiple times and you want to use one of the overloaded versions, consider using encode_with_selector

source

pub fn encode_with_selector<T: Tokenize>( &self, signature: Selector, args: T ) -> Result<Bytes, AbiError>

Returns the ABI encoded data for the provided function selector and arguments

source

pub fn decode<D: Detokenize, T: AsRef<[u8]>>( &self, name: &str, bytes: T ) -> Result<D, AbiError>

Decodes the provided ABI encoded function arguments with the selected function name.

If the function exists multiple times and you want to use one of the overloaded versions, consider using decode_with_selector

source

pub fn decode_raw<T: AsRef<[u8]>>( &self, name: &str, bytes: T ) -> Result<Vec<Token>, AbiError>

Decodes the provided ABI encoded function arguments with the selected function name.

If the function exists multiple times and you want to use one of the overloaded versions, consider using decode_with_selector

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn decode_output<D: Detokenize, T: AsRef<[u8]>>( &self, name: &str, bytes: T ) -> Result<D, AbiError>

Decodes the provided ABI encoded function output with the selected function name.

If the function exists multiple times and you want to use one of the overloaded versions, consider using decode_with_selector

source

pub fn decode_output_raw<T: AsRef<[u8]>>( &self, name: &str, bytes: T ) -> Result<Vec<Token>, AbiError>

Decodes the provided ABI encoded function output with the selected function name.

If the function exists multiple times and you want to use one of the overloaded versions, consider using decode_with_selector

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn decode_event<D: Detokenize>( &self, name: &str, topics: Vec<H256>, data: Bytes ) -> Result<D, AbiError>

Decodes for a given event name, given the log.topics and log.data fields from the transaction receipt

source

pub fn decode_event_raw( &self, name: &str, topics: Vec<H256>, data: Bytes ) -> Result<Vec<Token>, AbiError>

Decodes for a given event name, given the log.topics and log.data fields from the transaction receipt

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn decode_with_selector_raw<T: AsRef<[u8]>>( &self, signature: Selector, bytes: T ) -> Result<Vec<Token>, AbiError>

Decodes the provided ABI encoded bytes with the selected function selector

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn decode_with_selector<D: Detokenize, T: AsRef<[u8]>>( &self, signature: Selector, bytes: T ) -> Result<D, AbiError>

Decodes the provided ABI encoded bytes with the selected function selector

source

pub fn decode_input_raw<T: AsRef<[u8]>>( &self, bytes: T ) -> Result<Vec<Token>, AbiError>

Decodes the provided ABI encoded input bytes

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn decode_input<D: Detokenize, T: AsRef<[u8]>>( &self, bytes: T ) -> Result<D, AbiError>

Decodes the provided ABI encoded input bytes

source

pub fn decode_output_with_selector<D: Detokenize, T: AsRef<[u8]>>( &self, signature: Selector, bytes: T ) -> Result<D, AbiError>

Decode the provided ABI encoded bytes as the output of the provided function selector

source

pub fn decode_output_with_selector_raw<T: AsRef<[u8]>>( &self, signature: Selector, bytes: T ) -> Result<Vec<Token>, AbiError>

Decodes the provided ABI encoded bytes with the selected function selector

Returns a Token vector, which lets you decode function arguments dynamically without knowing the return type.

source

pub fn abi(&self) -> &Abi

Returns a reference to the contract’s ABI

Trait Implementations§

source§

impl<B, M> Clone for ContractInstance<B, M>
where B: Clone + Borrow<M>,

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<B: Debug, M: Debug> Debug for ContractInstance<B, M>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<B, M> Deref for ContractInstance<B, M>
where B: Borrow<M>,

§

type Target = BaseContract

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<M: Middleware> From<ContractInstance<Arc<M>, M>> for Multicall3<M>

Available on crate feature abigen only.
source§

fn from(contract: Contract<M>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<B, M> RefUnwindSafe for ContractInstance<B, M>

§

impl<B, M> Send for ContractInstance<B, M>
where B: Send, M: Send,

§

impl<B, M> Sync for ContractInstance<B, M>
where B: Sync, M: Sync,

§

impl<B, M> Unpin for ContractInstance<B, M>
where B: Unpin, M: Unpin,

§

impl<B, M> UnwindSafe for ContractInstance<B, M>
where B: UnwindSafe, M: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

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

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

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

source§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> JsonSchemaMaybe for T