integrate ENS at the provider level

This commit is contained in:
Georgios Konstantopoulos 2020-05-27 18:43:43 +03:00
parent 2e5ef68219
commit 6109003559
No known key found for this signature in database
GPG Key ID: FA607837CD26EDBC
17 changed files with 109 additions and 95 deletions

View File

@ -82,11 +82,11 @@ impl Context {
#struct_decl #struct_decl
impl<'a, S: Signer, P: JsonRpcClient> #name<'a, S, P> { impl<'a, P: JsonRpcClient, N: Network, S: Signer> #name<'a, P, N, S> {
/// Creates a new contract instance with the specified `ethers` /// Creates a new contract instance with the specified `ethers`
/// client at the given `Address`. The contract derefs to a `ethers::Contract` /// client at the given `Address`. The contract derefs to a `ethers::Contract`
/// object /// object
pub fn new<T: Into<Address>>(address: T, client: &'a Client<'a, S, P>) -> Self { pub fn new<T: Into<Address>>(address: T, client: &'a Client<'a, P, N, S>) -> Self {
let contract = Contract::new(client, &ABI, address.into()); let contract = Contract::new(client, &ABI, address.into());
Self(contract) Self(contract)
} }

View File

@ -13,7 +13,7 @@ pub(crate) fn imports() -> TokenStream {
Contract, ContractCall, Event, Lazy, Contract, ContractCall, Event, Lazy,
signers::{Client, Signer}, signers::{Client, Signer},
types::*, // import all the types so that we can codegen for everything types::*, // import all the types so that we can codegen for everything
providers::JsonRpcClient, providers::{JsonRpcClient, networks::Network},
}; };
} }
} }
@ -29,17 +29,17 @@ pub(crate) fn struct_declaration(cx: &Context) -> TokenStream {
// Struct declaration // Struct declaration
#[derive(Clone)] #[derive(Clone)]
pub struct #name<'a, S, P>(Contract<'a, S, P>); pub struct #name<'a, P, N, S>(Contract<'a, P, N, S>);
// Deref to the inner contract in order to access more specific functions functions // Deref to the inner contract in order to access more specific functions functions
impl<'a, S, P> std::ops::Deref for #name<'a, S, P> { impl<'a, P, N, S> std::ops::Deref for #name<'a, P, N, S> {
type Target = Contract<'a, S, P>; type Target = Contract<'a, P, N, S>;
fn deref(&self) -> &Self::Target { &self.0 } fn deref(&self) -> &Self::Target { &self.0 }
} }
impl<'a, S: Signer, P: JsonRpcClient> std::fmt::Debug for #name<'a, S, P> { impl<'a, P: JsonRpcClient, N: Network, S: Signer> std::fmt::Debug for #name<'a, P, N, S> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_tuple(stringify!(#name)) f.debug_tuple(stringify!(#name))
.field(&self.address()) .field(&self.address())

View File

@ -52,7 +52,7 @@ fn expand_filter(event: &Event) -> Result<TokenStream> {
Ok(quote! { Ok(quote! {
#doc #doc
pub fn #name<'b>(&'a self) -> Event<'a, 'b, P, #result> where 'a: 'b, { pub fn #name<'b>(&'a self) -> Event<'a, 'b, P, N, #result> where 'a: 'b, {
self.0.event(#ev_name).expect("event not found (this should never happen)") self.0.event(#ev_name).expect("event not found (this should never happen)")
} }
}) })
@ -314,7 +314,7 @@ mod tests {
assert_quote!(expand_filter(&event).unwrap(), { assert_quote!(expand_filter(&event).unwrap(), {
#[doc = "Gets the contract's `Transfer` event"] #[doc = "Gets the contract's `Transfer` event"]
pub fn transfer<'b>(&'a self) -> Event<'a, 'b, P, Transfer> pub fn transfer<'b>(&'a self) -> Event<'a, 'b, P, N, Transfer>
where where
'a: 'b, 'a: 'b,
{ {

View File

@ -40,9 +40,9 @@ fn expand_function(function: &Function, alias: Option<Ident>) -> Result<TokenStr
let outputs = expand_fn_outputs(&function.outputs)?; let outputs = expand_fn_outputs(&function.outputs)?;
let result = if function.constant { let result = if function.constant {
quote! { ContractCall<'a, S, P, #outputs> } quote! { ContractCall<'a, P, N, S, #outputs> }
} else { } else {
quote! { ContractCall<'a, S, P, H256> } quote! { ContractCall<'a, P, N, S, H256> }
}; };
let arg = expand_inputs_call_arg(&function.inputs); let arg = expand_inputs_call_arg(&function.inputs);

View File

@ -1,5 +1,5 @@
use ethers_abi::{Detokenize, Function}; use ethers_abi::{Detokenize, Function};
use ethers_providers::JsonRpcClient; use ethers_providers::{networks::Network, JsonRpcClient};
use ethers_signers::{Client, Signer}; use ethers_signers::{Client, Signer};
use ethers_types::{Address, BlockNumber, TransactionRequest, H256, U256}; use ethers_types::{Address, BlockNumber, TransactionRequest, H256, U256};
@ -7,15 +7,15 @@ use std::{fmt::Debug, marker::PhantomData};
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
pub struct ContractCall<'a, S, P, D> { pub struct ContractCall<'a, P, N, S, D> {
pub(crate) tx: TransactionRequest, pub(crate) tx: TransactionRequest,
pub(crate) function: Function, pub(crate) function: Function,
pub(crate) client: &'a Client<'a, S, P>, pub(crate) client: &'a Client<'a, P, N, S>,
pub(crate) block: Option<BlockNumber>, pub(crate) block: Option<BlockNumber>,
pub(crate) datatype: PhantomData<D>, pub(crate) datatype: PhantomData<D>,
} }
impl<'a, S, P, D: Detokenize> ContractCall<'a, S, P, D> { impl<'a, P, N, S, D: Detokenize> ContractCall<'a, S, P, N, D> {
/// Sets the `from` field in the transaction to the provided value /// Sets the `from` field in the transaction to the provided value
pub fn from<T: Into<Address>>(mut self, from: T) -> Self { pub fn from<T: Into<Address>>(mut self, from: T) -> Self {
self.tx.from = Some(from.into()); self.tx.from = Some(from.into());
@ -55,9 +55,13 @@ where
CallError(P::Error), CallError(P::Error),
} }
impl<'a, S: Signer, P: JsonRpcClient, D: Detokenize> ContractCall<'a, S, P, D> impl<'a, P, N, S, D> ContractCall<'a, P, N, S, D>
where where
S: Signer,
P: JsonRpcClient,
P::Error: 'static, P::Error: 'static,
N: Network,
D: Detokenize,
{ {
/// Queries the blockchain via an `eth_call` for the provided transaction. /// Queries the blockchain via an `eth_call` for the provided transaction.
/// ///

View File

@ -1,7 +1,7 @@
use crate::{ContractCall, Event}; use crate::{ContractCall, Event};
use ethers_abi::{Abi, Detokenize, Error, EventExt, Function, FunctionExt, Tokenize}; use ethers_abi::{Abi, Detokenize, Error, EventExt, Function, FunctionExt, Tokenize};
use ethers_providers::JsonRpcClient; use ethers_providers::{networks::Network, JsonRpcClient};
use ethers_signers::{Client, Signer}; use ethers_signers::{Client, Signer};
use ethers_types::{Address, Filter, Selector, TransactionRequest}; use ethers_types::{Address, Filter, Selector, TransactionRequest};
@ -13,8 +13,8 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash, marker::PhantomData};
// TODO: Should we separate the lifetimes for the two references? // TODO: Should we separate the lifetimes for the two references?
// https://stackoverflow.com/a/29862184 // https://stackoverflow.com/a/29862184
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Contract<'a, S, P> { pub struct Contract<'a, P, N, S> {
client: &'a Client<'a, S, P>, client: &'a Client<'a, P, N, S>,
abi: &'a Abi, abi: &'a Abi,
address: Address, address: Address,
@ -25,9 +25,9 @@ pub struct Contract<'a, S, P> {
methods: HashMap<Selector, (String, usize)>, methods: HashMap<Selector, (String, usize)>,
} }
impl<'a, S: Signer, P: JsonRpcClient> Contract<'a, S, P> { impl<'a, P: JsonRpcClient, N: Network, S: Signer> Contract<'a, P, N, S> {
/// Creates a new contract from the provided client, abi and address /// Creates a new contract from the provided client, abi and address
pub fn new(client: &'a Client<'a, S, P>, abi: &'a Abi, address: Address) -> Self { pub fn new(client: &'a Client<'a, P, N, S>, abi: &'a Abi, address: Address) -> Self {
let methods = create_mapping(&abi.functions, |function| function.selector()); let methods = create_mapping(&abi.functions, |function| function.selector());
Self { Self {
@ -41,7 +41,7 @@ impl<'a, S: Signer, P: JsonRpcClient> Contract<'a, S, P> {
/// Returns an `Event` builder for the provided event name. If there are /// Returns an `Event` builder for the provided event name. If there are
/// multiple functions with the same name due to overloading, consider using /// multiple functions with the same name due to overloading, consider using
/// the `method_hash` method instead, since this will use the first match. /// the `method_hash` method instead, since this will use the first match.
pub fn event<'b, D: Detokenize>(&'a self, name: &str) -> Result<Event<'a, 'b, P, D>, Error> pub fn event<'b, D: Detokenize>(&'a self, name: &str) -> Result<Event<'a, 'b, P, N, D>, Error>
where where
'a: 'b, 'a: 'b,
{ {
@ -62,7 +62,7 @@ impl<'a, S: Signer, P: JsonRpcClient> Contract<'a, S, P> {
&self, &self,
name: &str, name: &str,
args: T, args: T,
) -> Result<ContractCall<'a, S, P, D>, Error> { ) -> Result<ContractCall<'a, P, N, S, D>, Error> {
// get the function // get the function
let function = self.abi.function(name)?; let function = self.abi.function(name)?;
self.method_func(function, args) self.method_func(function, args)
@ -74,7 +74,7 @@ impl<'a, S: Signer, P: JsonRpcClient> Contract<'a, S, P> {
&self, &self,
signature: Selector, signature: Selector,
args: T, args: T,
) -> Result<ContractCall<'a, S, P, D>, Error> { ) -> Result<ContractCall<'a, P, N, S, D>, Error> {
let function = self let function = self
.methods .methods
.get(&signature) .get(&signature)
@ -87,7 +87,7 @@ impl<'a, S: Signer, P: JsonRpcClient> Contract<'a, S, P> {
&self, &self,
function: &Function, function: &Function,
args: T, args: T,
) -> Result<ContractCall<'a, S, P, D>, Error> { ) -> Result<ContractCall<'a, P, N, S, D>, Error> {
// create the calldata // create the calldata
let data = function.encode_input(&args.into_tokens())?; let data = function.encode_input(&args.into_tokens())?;

View File

@ -1,21 +1,21 @@
use crate::ContractError; use crate::ContractError;
use ethers_abi::{Detokenize, Event as AbiEvent, RawLog}; use ethers_abi::{Detokenize, Event as AbiEvent, RawLog};
use ethers_providers::{JsonRpcClient, Provider}; use ethers_providers::{networks::Network, JsonRpcClient, Provider};
use ethers_types::{BlockNumber, Filter, ValueOrArray, H256}; use ethers_types::{BlockNumber, Filter, ValueOrArray, H256};
use std::marker::PhantomData; use std::marker::PhantomData;
pub struct Event<'a, 'b, P, D> { pub struct Event<'a, 'b, P, N, D> {
pub filter: Filter, pub filter: Filter,
pub(crate) provider: &'a Provider<P>, pub(crate) provider: &'a Provider<P, N>,
pub(crate) event: &'b AbiEvent, pub(crate) event: &'b AbiEvent,
pub(crate) datatype: PhantomData<D>, pub(crate) datatype: PhantomData<D>,
} }
// TODO: Improve these functions // TODO: Improve these functions
impl<'a, 'b, P, D: Detokenize> Event<'a, 'b, P, D> { impl<'a, 'b, P, N, D: Detokenize> Event<'a, 'b, P, N, D> {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
pub fn from_block<T: Into<BlockNumber>>(mut self, block: T) -> Self { pub fn from_block<T: Into<BlockNumber>>(mut self, block: T) -> Self {
self.filter.from_block = Some(block.into()); self.filter.from_block = Some(block.into());
@ -40,7 +40,7 @@ impl<'a, 'b, P, D: Detokenize> Event<'a, 'b, P, D> {
} }
// TODO: Can we get rid of the static? // TODO: Can we get rid of the static?
impl<'a, 'b, P: JsonRpcClient, D: Detokenize> Event<'a, 'b, P, D> impl<'a, 'b, P: JsonRpcClient, N: Network, D: Detokenize> Event<'a, 'b, P, N, D>
where where
P::Error: 'static, P::Error: 'static,
{ {

View File

@ -74,7 +74,9 @@ mod tests {
#[test] #[test]
fn test_namehash() { fn test_namehash() {
dbg!(ethers_utils::id("name(bytes32)")); dbg!("00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
.from_hex::<Vec<u8>>()
.unwrap());
for (name, expected) in &[ for (name, expected) in &[
( (
"", "",

View File

@ -7,6 +7,8 @@
mod http; mod http;
mod provider; mod provider;
pub mod networks;
/// ENS support /// ENS support
pub mod ens; pub mod ens;
@ -17,7 +19,7 @@ use std::{error::Error, fmt::Debug};
pub use provider::Provider; pub use provider::Provider;
/// An HTTP provider for interacting with an Ethereum-compatible blockchain /// An HTTP provider for interacting with an Ethereum-compatible blockchain
pub type HttpProvider = Provider<http::Provider>; pub type HttpProvider<N> = Provider<http::Provider, N>;
#[async_trait] #[async_trait]
/// Implement this trait in order to plug in different backends /// Implement this trait in order to plug in different backends

View File

@ -2,10 +2,11 @@
//! a transaction that is designed to work with testnet does not accidentally work //! a transaction that is designed to work with testnet does not accidentally work
//! with mainnet because the URL was changed. //! with mainnet because the URL was changed.
use ethers_types::U64; use ethers_types::{Address, H160, U64};
pub trait Network { pub trait Network {
const CHAIN_ID: Option<U64>; const CHAIN_ID: Option<U64>;
const ENS_ADDRESS: Option<Address>;
// TODO: Default providers? e.g. `mainnet.infura.io/XXX`? // TODO: Default providers? e.g. `mainnet.infura.io/XXX`?
} }
@ -15,25 +16,19 @@ pub struct Mainnet;
impl Network for Mainnet { impl Network for Mainnet {
const CHAIN_ID: Option<U64> = Some(U64([1])); const CHAIN_ID: Option<U64> = Some(U64([1]));
// 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
const ENS_ADDRESS: Option<Address> = Some(H160([
// cannot set type aliases as constructors
0, 0, 0, 0, 0, 12, 46, 7, 78, 198, 154, 13, 251, 41, 151, 186, 108, 125, 46, 30,
]));
} }
/// No EIP155 /// No EIP155
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct EIP155Disabled; pub struct Any;
// EIP155 being disabled means no chainId will be used impl Network for Any {
impl Network for EIP155Disabled {
const CHAIN_ID: Option<U64> = None; const CHAIN_ID: Option<U64> = None;
} const ENS_ADDRESS: Option<Address> = None;
pub mod instantiated {
use super::*;
use crate::Wallet;
/// A Wallet instantiated with chain_id = 1 for Ethereum Mainnet.
pub type MainnetWallet = Wallet<Mainnet>;
/// A wallet which does not use EIP-155 and does not take the chain id into account
/// when creating transactions
pub type AnyWallet = Wallet<EIP155Disabled>;
} }

View File

@ -1,4 +1,4 @@
use crate::{ens, http::Provider as HttpProvider, JsonRpcClient}; use crate::{ens, http::Provider as HttpProvider, networks::Network, JsonRpcClient};
use ethers_abi::{Detokenize, ParamType}; use ethers_abi::{Detokenize, ParamType};
use ethers_types::{ use ethers_types::{
@ -10,15 +10,15 @@ use ethers_utils as utils;
use serde::Deserialize; use serde::Deserialize;
use url::{ParseError, Url}; use url::{ParseError, Url};
use std::{convert::TryFrom, fmt::Debug}; use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
/// An abstract provider for interacting with the [Ethereum JSON RPC /// An abstract provider for interacting with the [Ethereum JSON RPC
/// API](https://github.com/ethereum/wiki/wiki/JSON-RPC) /// API](https://github.com/ethereum/wiki/wiki/JSON-RPC)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Provider<P>(P, Option<Address>); pub struct Provider<P, N>(P, PhantomData<N>, Option<Address>);
// JSON RPC bindings // JSON RPC bindings
impl<P: JsonRpcClient> Provider<P> { impl<P: JsonRpcClient, N: Network> Provider<P, N> {
////// Blockchain Status ////// Blockchain Status
// //
// Functions for querying the state of the blockchain // Functions for querying the state of the blockchain
@ -206,10 +206,13 @@ impl<P: JsonRpcClient> Provider<P> {
ens_name: &str, ens_name: &str,
selector: Selector, selector: Selector,
) -> Result<Option<T>, P::Error> { ) -> Result<Option<T>, P::Error> {
let ens_addr = if let Some(ens_addr) = self.1 { // Get the ENS address, prioritize the local override variable
ens_addr let ens_addr = match self.2 {
} else { Some(ens_addr) => ens_addr,
return Ok(None); None => match N::ENS_ADDRESS {
Some(ens_addr) => ens_addr,
None => return Ok(None),
},
}; };
// first get the resolver responsible for this name // first get the resolver responsible for this name
@ -231,8 +234,8 @@ impl<P: JsonRpcClient> Provider<P> {
Ok(Some(decode_bytes(param, data))) Ok(Some(decode_bytes(param, data)))
} }
pub fn ens<T: Into<Address>>(mut self, ens_addr: T) -> Self { pub fn ens<T: Into<Address>>(mut self, ens: T) -> Self {
self.1 = Some(ens_addr.into()); self.2 = Some(ens.into());
self self
} }
} }
@ -248,30 +251,30 @@ fn decode_bytes<T: Detokenize>(param: ParamType, bytes: Bytes) -> T {
T::from_tokens(tokens).expect("could not parse tokens as address") T::from_tokens(tokens).expect("could not parse tokens as address")
} }
impl TryFrom<&str> for Provider<HttpProvider> { impl<N: Network> TryFrom<&str> for Provider<HttpProvider, N> {
type Error = ParseError; type Error = ParseError;
fn try_from(src: &str) -> Result<Self, Self::Error> { fn try_from(src: &str) -> Result<Self, Self::Error> {
Ok(Provider(HttpProvider::new(Url::parse(src)?), None)) Ok(Provider(
HttpProvider::new(Url::parse(src)?),
PhantomData,
None,
))
} }
} }
#[cfg(test)] #[cfg(test)]
mod ens_tests { mod ens_tests {
use super::*; use super::*;
use crate::networks::Mainnet;
#[tokio::test] #[tokio::test]
// Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2 // Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2
async fn mainnet_resolve_name() { async fn mainnet_resolve_name() {
let mainnet_ens_addr = "00000000000C2E074eC69A0dFb2997BA6C7d2e1e" let provider = Provider::<HttpProvider, Mainnet>::try_from(
.parse::<Address>()
.unwrap();
let provider = Provider::<HttpProvider>::try_from(
"https://mainnet.infura.io/v3/9408f47dedf04716a03ef994182cf150", "https://mainnet.infura.io/v3/9408f47dedf04716a03ef994182cf150",
) )
.unwrap() .unwrap();
.ens(mainnet_ens_addr);
let addr = provider let addr = provider
.resolve_name("registrar.firefly.eth") .resolve_name("registrar.firefly.eth")
@ -297,15 +300,10 @@ mod ens_tests {
#[tokio::test] #[tokio::test]
// Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2 // Test vector from: https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#id2
async fn mainnet_lookup_address() { async fn mainnet_lookup_address() {
let mainnet_ens_addr = "00000000000C2E074eC69A0dFb2997BA6C7d2e1e" let provider = Provider::<HttpProvider, Mainnet>::try_from(
.parse::<Address>()
.unwrap();
let provider = Provider::<HttpProvider>::try_from(
"https://mainnet.infura.io/v3/9408f47dedf04716a03ef994182cf150", "https://mainnet.infura.io/v3/9408f47dedf04716a03ef994182cf150",
) )
.unwrap() .unwrap();
.ens(mainnet_ens_addr);
let name = provider let name = provider
.lookup_address("6fC21092DA55B392b045eD78F4732bff3C580e2c".parse().unwrap()) .lookup_address("6fC21092DA55B392b045eD78F4732bff3C580e2c".parse().unwrap())

View File

@ -1,18 +1,18 @@
use crate::Signer; use crate::Signer;
use ethers_providers::{JsonRpcClient, Provider}; use ethers_providers::{networks::Network, JsonRpcClient, Provider};
use ethers_types::{Address, BlockNumber, TransactionRequest, TxHash}; use ethers_types::{Address, BlockNumber, TransactionRequest, TxHash};
use std::ops::Deref; use std::ops::Deref;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Client<'a, S, P> { pub struct Client<'a, P, N, S> {
pub(crate) provider: &'a Provider<P>, pub(crate) provider: &'a Provider<P, N>,
pub(crate) signer: Option<S>, pub(crate) signer: Option<S>,
} }
impl<'a, S, P> From<&'a Provider<P>> for Client<'a, S, P> { impl<'a, P, N, S> From<&'a Provider<P, N>> for Client<'a, P, N, S> {
fn from(provider: &'a Provider<P>) -> Self { fn from(provider: &'a Provider<P, N>) -> Self {
Client { Client {
provider, provider,
signer: None, signer: None,
@ -20,7 +20,12 @@ impl<'a, S, P> From<&'a Provider<P>> for Client<'a, S, P> {
} }
} }
impl<'a, S: Signer, P: JsonRpcClient> Client<'a, S, P> { impl<'a, P, N, S> Client<'a, P, N, S>
where
S: Signer,
P: JsonRpcClient,
N: Network,
{
/// Signs the transaction and then broadcasts its RLP encoding via the `eth_sendRawTransaction` /// Signs the transaction and then broadcasts its RLP encoding via the `eth_sendRawTransaction`
/// API /// API
pub async fn send_transaction( pub async fn send_transaction(
@ -84,7 +89,7 @@ impl<'a, S: Signer, P: JsonRpcClient> Client<'a, S, P> {
.unwrap_or_default() .unwrap_or_default()
} }
pub fn provider(&self) -> &Provider<P> { pub fn provider(&self) -> &Provider<P, N> {
self.provider self.provider
} }
} }
@ -92,8 +97,11 @@ impl<'a, S: Signer, P: JsonRpcClient> Client<'a, S, P> {
// Abuse Deref to use the Provider's methods without re-writing everything. // Abuse Deref to use the Provider's methods without re-writing everything.
// This is an anti-pattern and should not be encouraged, but this improves the UX while // This is an anti-pattern and should not be encouraged, but this improves the UX while
// keeping the LoC low // keeping the LoC low
impl<'a, S, P> Deref for Client<'a, S, P> { impl<'a, P, N, S> Deref for Client<'a, P, N, S>
type Target = &'a Provider<P>; where
N: 'a,
{
type Target = &'a Provider<P, N>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.provider &self.provider

View File

@ -10,10 +10,6 @@
//! //!
//! TODO: We might need a `SignerAsync` trait for HSM use cases? //! TODO: We might need a `SignerAsync` trait for HSM use cases?
mod networks;
pub use networks::instantiated::*;
use networks::Network;
mod wallet; mod wallet;
pub use wallet::Wallet; pub use wallet::Wallet;
@ -37,3 +33,12 @@ pub trait Signer {
/// Returns the signer's Ethereum Address /// Returns the signer's Ethereum Address
fn address(&self) -> Address; fn address(&self) -> Address;
} }
use ethers_providers::networks::{Any, Mainnet};
/// A Wallet instantiated with chain_id = 1 for Ethereum Mainnet.
pub type MainnetWallet = Wallet<Mainnet>;
/// A wallet which does not use EIP-155 and does not take the chain id into account
/// when creating transactions
pub type AnyWallet = Wallet<Any>;

View File

@ -1,6 +1,6 @@
use crate::{Client, Network, Signer}; use crate::{Client, Signer};
use ethers_providers::{JsonRpcClient, Provider}; use ethers_providers::{networks::Network, JsonRpcClient, Provider};
use ethers_types::{ use ethers_types::{
rand::Rng, secp256k1, Address, PrivateKey, PublicKey, Signature, Transaction, rand::Rng, secp256k1, Address, PrivateKey, PublicKey, Signature, Transaction,
@ -52,7 +52,7 @@ impl<N: Network> Wallet<N> {
} }
/// Connects to a provider and returns a client /// Connects to a provider and returns a client
pub fn connect<P: JsonRpcClient>(self, provider: &Provider<P>) -> Client<Wallet<N>, P> { pub fn connect<P: JsonRpcClient>(self, provider: &Provider<P, N>) -> Client<P, N, Wallet<N>> {
Client { Client {
signer: Some(self), signer: Some(self),
provider, provider,

View File

@ -4,7 +4,7 @@ pub type Selector = [u8; 4];
// Re-export common ethereum datatypes with more specific names // Re-export common ethereum datatypes with more specific names
pub use ethereum_types::H256 as TxHash; pub use ethereum_types::H256 as TxHash;
pub use ethereum_types::{Address, Bloom, H256, U128, U256, U64}; pub use ethereum_types::{Address, Bloom, H160, H256, U128, U256, U64};
mod transaction; mod transaction;
pub use transaction::{Overrides, Transaction, TransactionReceipt, TransactionRequest}; pub use transaction::{Overrides, Transaction, TransactionReceipt, TransactionRequest};

View File

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use ethers::{ use ethers::{
providers::HttpProvider, providers::{networks::Any, HttpProvider},
types::{Address, Filter}, types::{Address, Filter},
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
@ -8,7 +8,7 @@ use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// connect to the network // connect to the network
let provider = HttpProvider::try_from("http://localhost:8545")?; let provider = HttpProvider::<Any>::try_from("http://localhost:8545")?;
let filter = Filter::new() let filter = Filter::new()
.address_str("f817796F60D268A36a57b8D2dF1B97B14C0D0E1d")? .address_str("f817796F60D268A36a57b8D2dF1B97B14C0D0E1d")?

View File

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use ethers::{ use ethers::{
providers::HttpProvider, providers::{networks::Any, HttpProvider},
types::{BlockNumber, TransactionRequest}, types::{BlockNumber, TransactionRequest},
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
@ -8,7 +8,7 @@ use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// connect to the network // connect to the network
let provider = HttpProvider::try_from("http://localhost:8545")?; let provider = HttpProvider::<Any>::try_from("http://localhost:8545")?;
let accounts = provider.get_accounts().await?; let accounts = provider.get_accounts().await?;
let from = accounts[0]; let from = accounts[0];