use crate::{ContractCall, Event}; use ethers_core::{ abi::{Abi, Detokenize, Error, EventExt, Function, FunctionExt, Tokenize}, types::{Address, Filter, NameOrAddress, Selector, TransactionRequest}, }; use ethers_providers::JsonRpcClient; use ethers_signers::{Client, Signer}; use rustc_hex::ToHex; use std::{collections::HashMap, fmt::Debug, hash::Hash, marker::PhantomData}; /// Represents a contract instance at an address. Provides methods for /// contract interaction. // TODO: Should we separate the lifetimes for the two references? // https://stackoverflow.com/a/29862184 #[derive(Debug, Clone)] pub struct Contract<'a, P, S> { client: &'a Client
,
abi: &'a Abi,
address: Address,
/// A mapping from method signature to a name-index pair for accessing
/// functions in the contract ABI. This is used to avoid allocation when
/// searching for matching functions by signature.
// Adapted from: https://github.com/gnosis/ethcontract-rs/blob/master/src/contract.rs
methods: HashMap ) -> Self {
let methods = create_mapping(&abi.functions, |function| function.selector());
Self {
client,
abi,
address,
methods,
}
}
/// Returns an `Event` builder for the provided event name.
pub fn event ) -> Self {
let mut this = self.clone();
this.client = client;
this
}
/// Returns the contract's address
pub fn address(&self) -> Address {
self.address
}
/// Returns a reference to the contract's ABI
pub fn abi(&self) -> &Abi {
&self.abi
}
/// Returns a reference to the contract's client
pub fn client(&self) -> &Client {
&self.client
}
}
/// Utility function for creating a mapping between a unique signature and a
/// name-index pair for accessing contract ABI items.
fn create_mapping
where
S: Hash + Eq,
F: Fn(&T) -> S,
{
let signature = &signature;
elements
.iter()
.flat_map(|(name, sub_elements)| {
sub_elements
.iter()
.enumerate()
.map(move |(index, element)| (signature(element), (name.to_owned(), index)))
})
.collect()
}