integrate ENS at the provider level
This commit is contained in:
parent
2e5ef68219
commit
6109003559
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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())?;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 &[
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>;
|
|
||||||
}
|
}
|
|
@ -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())
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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")?
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue