Upgrade to Tokio 1.0 and remove async-std (#120)

* feat(providers): tokio 1.0

BREAKING: This removes async-std as a compatibility option

* feat: tokio 1.0 in rest of crates

* fix: patch Cargo.toml until deps are released

* fix(contract): load ws deps

* feat: bytes 1.0 (#121)

* feat(core): move to bytes::Bytes

* feat: adjust rest of crates to Bytes

* chore: bump deps

CI fails due to:
https://github.com/snapview/tokio-tungstenite/pull/142#discussion_r550445144

* chore: use latest tokio-tungstenite

* ci: split tests into jobs (#129)

* Switch to `hex` (#128)

* fix(core): replace rustc_hex with hex

* fix(providers): replace rustc_hex with hex

* chore: replace rustc-hex with hex

* chore: cargo fmt

* fix(ledger): copy address from string correctly

* chore: fix flaky tests

Fixes #105
This commit is contained in:
Georgios Konstantopoulos 2020-12-31 19:19:14 +02:00 committed by GitHub
parent 7eec705cec
commit 5c1f8f532a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 414 additions and 876 deletions

View File

@ -15,16 +15,12 @@ jobs:
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install ganache-cli - name: Install ganache-cli
uses: actions/setup-node@v1 uses: actions/setup-node@v1
with: with:
node-version: 10 node-version: 10
- name: Install ganache - name: Install ganache
run: npm install -g ganache-cli run: npm install -g ganache-cli
- name: Install libusb (for Ledger)
run: sudo apt update && sudo apt install pkg-config libudev-dev
- name: Install Solc - name: Install Solc
run: | run: |
mkdir -p "$HOME/bin" mkdir -p "$HOME/bin"
@ -42,7 +38,6 @@ jobs:
chmod u+x "$HOME/bin/geth" chmod u+x "$HOME/bin/geth"
export PATH=$HOME/bin:$PATH export PATH=$HOME/bin:$PATH
geth version geth version
- name: Install stable toolchain - name: Install stable toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -50,19 +45,69 @@ jobs:
toolchain: stable toolchain: stable
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: cargo test - name: cargo test
run: | run: |
export PATH=$HOME/bin:$PATH export PATH=$HOME/bin:$PATH
cargo test cargo test
feature-tests:
name: Check
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install ganache-cli
uses: actions/setup-node@v1
with:
node-version: 10
# TODO: can we combine these shared steps in github actions?
- name: Install ganache
run: npm install -g ganache-cli
- name: Install Solc
run: |
mkdir -p "$HOME/bin"
wget -q https://github.com/ethereum/solidity/releases/download/v0.6.6/solc-static-linux -O $HOME/bin/solc
chmod u+x "$HOME/bin/solc"
export PATH=$HOME/bin:$PATH
solc --version
- name: Install geth
run: |
mkdir -p "$HOME/bin"
wget -q https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.23-8c2f2715.tar.gz
tar -xvf geth-linux-amd64-1.9.23-8c2f2715.tar.gz
mv geth-linux-amd64-1.9.23-8c2f2715/geth $HOME/bin/geth
chmod u+x "$HOME/bin/geth"
export PATH=$HOME/bin:$PATH
geth version
- name: Install libusb (for Ledger)
run: sudo apt update && sudo apt install pkg-config libudev-dev
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: cargo test (Celo) - name: cargo test (Celo)
run: | run: |
export PATH=$HOME/bin:$PATH export PATH=$HOME/bin:$PATH
cargo test --all-features cargo test --all-features
lint:
name: Check
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: cargo fmt - name: cargo fmt
run: cargo fmt --all -- --check run: cargo fmt --all -- --check
- name: cargo clippy - name: cargo clippy
run: cargo clippy -- -D warnings run: cargo clippy -- -D warnings

756
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,3 +8,7 @@ members = [
"./ethers-core", "./ethers-core",
"./ethers-middleware", "./ethers-middleware",
] ]
[patch.crates-io]
reqwest = { git = "https://github.com/seanmonstar/reqwest", branch = "master" }
tokio-tungstenite = { git = "https://github.com/dnaka91/tokio-tungstenite", branch = "tokio-1.0" }

View File

@ -17,16 +17,17 @@ ethers-contract-abigen = { version = "0.1.3", path = "ethers-contract-abigen", o
ethers-contract-derive = { version = "0.1.3", path = "ethers-contract-derive", optional = true } ethers-contract-derive = { version = "0.1.3", path = "ethers-contract-derive", optional = true }
serde = { version = "1.0.118", default-features = false } serde = { version = "1.0.118", default-features = false }
serde_json = { version = "1.0.60", default-features = false } serde_json = { version = "1.0.61", default-features = false }
rustc-hex = { version = "2.1.0", default-features = false } thiserror = { version = "1.0.23", default-features = false }
thiserror = { version = "1.0.22", default-features = false }
once_cell = { version = "1.5.2", default-features = false } once_cell = { version = "1.5.2", default-features = false }
pin-project = {version = "1.0.2", default-features = false } pin-project = {version = "1.0.2", default-features = false }
futures-util = { version = "0.3.8", default-features = false } futures-util = { version = "0.3.8", default-features = false }
hex = { version = "0.4.2", default-features = false, features = ["std"] }
[dev-dependencies] [dev-dependencies]
ethers = { version = "0.1.3", path = "../ethers" } ethers = { version = "0.1.3", path = "../ethers" }
tokio = { version = "0.2.21", default-features = false, features = ["macros"] } ethers-providers = { version = "0.1.3", path = "../ethers-providers", default-features = false, features = ["ws"] }
tokio = { version = "1.0", default-features = false, features = ["macros"] }
ethers-signers = { version = "0.1.3", path = "../ethers-signers" } ethers-signers = { version = "0.1.3", path = "../ethers-signers" }
ethers-middleware = { version = "0.1.3", path = "../ethers-middleware" } ethers-middleware = { version = "0.1.3", path = "../ethers-middleware" }

View File

@ -12,16 +12,15 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
[dependencies] [dependencies]
ethers-core = { version = "0.1.3", path = "../../ethers-core" } ethers-core = { version = "0.1.3", path = "../../ethers-core" }
anyhow = "1.0.36" anyhow = "1.0.37"
curl = "0.4" curl = "0.4"
Inflector = "0.11" Inflector = "0.11"
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = "1.0.12" syn = "1.0.12"
url = "2.1" url = "2.1"
serde_json = "1.0.53" serde_json = "1.0.61"
once_cell = "1.3.1" hex = { version = "0.4.2", default-features = false, features = ["std"] }
rustc-hex = { version = "2.1.0", default-features = false }
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@ -8,7 +8,6 @@ use anyhow::{anyhow, Context as _, Result};
use inflector::Inflector; use inflector::Inflector;
use proc_macro2::{Literal, TokenStream}; use proc_macro2::{Literal, TokenStream};
use quote::quote; use quote::quote;
use rustc_hex::ToHex;
use syn::Ident; use syn::Ident;
/// Expands a context into a method struct containing all the generated bindings /// Expands a context into a method struct containing all the generated bindings
@ -46,7 +45,7 @@ fn expand_function(function: &Function, alias: Option<Ident>) -> Result<TokenStr
let doc = util::expand_doc(&format!( let doc = util::expand_doc(&format!(
"Calls the contract's `{}` (0x{}) function", "Calls the contract's `{}` (0x{}) function",
function.name, function.name,
function.selector().to_hex::<String>() hex::encode(function.selector())
)); ));
Ok(quote! { Ok(quote! {

View File

@ -8,7 +8,6 @@ use ethers_core::{
}; };
use ethers_providers::Middleware; use ethers_providers::Middleware;
use rustc_hex::ToHex;
use std::{collections::HashMap, fmt::Debug, hash::Hash, sync::Arc}; use std::{collections::HashMap, fmt::Debug, hash::Hash, sync::Arc};
use thiserror::Error; use thiserror::Error;
@ -107,7 +106,7 @@ impl BaseContract {
.methods .methods
.get(&signature) .get(&signature)
.map(|(name, index)| &self.abi.functions[name][*index]) .map(|(name, index)| &self.abi.functions[name][*index])
.ok_or_else(|| Error::InvalidName(signature.to_hex::<String>()))?) .ok_or_else(|| Error::InvalidName(hex::encode(signature)))?)
} }
/// Returns a reference to the contract's ABI /// Returns a reference to the contract's ABI
@ -139,7 +138,7 @@ pub(crate) fn decode_event<D: Detokenize>(
let tokens = event let tokens = event
.parse_log(RawLog { .parse_log(RawLog {
topics, topics,
data: data.0, data: data.to_vec(),
})? })?
.params .params
.into_iter() .into_iter()
@ -199,7 +198,6 @@ where
mod tests { mod tests {
use super::*; use super::*;
use ethers_core::{abi::parse_abi, types::U256}; use ethers_core::{abi::parse_abi, types::U256};
use rustc_hex::FromHex;
#[test] #[test]
fn can_parse_function_inputs() { fn can_parse_function_inputs() {
@ -214,7 +212,7 @@ mod tests {
let encoded = abi.encode("approve", (spender, amount)).unwrap(); let encoded = abi.encode("approve", (spender, amount)).unwrap();
assert_eq!(encoded.0.to_hex::<String>(), "095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); assert_eq!(hex::encode(&encoded), "095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
let (spender2, amount2): (Address, U256) = abi.decode("approve", encoded).unwrap(); let (spender2, amount2): (Address, U256) = abi.decode("approve", encoded).unwrap();
assert_eq!(spender, spender2); assert_eq!(spender, spender2);
@ -239,8 +237,7 @@ mod tests {
.map(|hash| hash.parse::<H256>().unwrap()) .map(|hash| hash.parse::<H256>().unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let data = Bytes::from( let data = Bytes::from(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" hex::decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
.from_hex::<Vec<u8>>()
.unwrap(), .unwrap(),
); );

View File

@ -10,7 +10,6 @@ use ethers_core::{
}; };
use ethers_providers::Middleware; use ethers_providers::Middleware;
use rustc_hex::ToHex;
use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use std::{fmt::Debug, marker::PhantomData, sync::Arc};
/// A Contract is an abstraction of an executable program on the Ethereum Blockchain. /// A Contract is an abstraction of an executable program on the Ethereum Blockchain.
@ -219,7 +218,7 @@ impl<M: Middleware> Contract<M> {
.methods .methods
.get(&signature) .get(&signature)
.map(|(name, index)| &self.base_contract.abi.functions[name][*index]) .map(|(name, index)| &self.base_contract.abi.functions[name][*index])
.ok_or_else(|| Error::InvalidName(signature.to_hex::<String>()))?; .ok_or_else(|| Error::InvalidName(hex::encode(signature)))?;
self.method_func(function, args) self.method_func(function, args)
} }

View File

@ -143,9 +143,9 @@ impl<M: Middleware> ContractFactory<M> {
return Err(ContractError::ConstructorError); return Err(ContractError::ConstructorError);
} }
(None, true) => self.bytecode.clone(), (None, true) => self.bytecode.clone(),
(Some(constructor), _) => { (Some(constructor), _) => constructor
Bytes(constructor.encode_input(self.bytecode.0.clone(), &params)?) .encode_input(self.bytecode.to_vec(), &params)?
} .into(),
}; };
// create the tx object. Since we're deploying a contract, `to` is `None` // create the tx object. Since we're deploying a contract, `to` is `None`

View File

@ -1,6 +1,6 @@
use ethers_core::{ use ethers_core::{
abi::{Detokenize, Function, Token}, abi::{Detokenize, Function, Token},
types::{Address, BlockNumber, NameOrAddress, TxHash, U256}, types::{Address, BlockNumber, Bytes, NameOrAddress, TxHash, U256},
}; };
use ethers_providers::Middleware; use ethers_providers::Middleware;
@ -139,7 +139,7 @@ pub struct Multicall<M> {
/// with `data` /// with `data`
pub struct Call { pub struct Call {
target: Address, target: Address,
data: Vec<u8>, data: Bytes,
function: Function, function: Function,
} }
@ -207,7 +207,7 @@ impl<M: Middleware> Multicall<M> {
(Some(NameOrAddress::Address(target)), Some(data)) => { (Some(NameOrAddress::Address(target)), Some(data)) => {
let call = Call { let call = Call {
target, target,
data: data.0, data,
function: call.function, function: call.function,
}; };
self.calls.push(call); self.calls.push(call);
@ -357,7 +357,7 @@ impl<M: Middleware> Multicall<M> {
let calls: Vec<(Address, Vec<u8>)> = self let calls: Vec<(Address, Vec<u8>)> = self
.calls .calls
.iter() .iter()
.map(|call| (call.target, call.data.clone())) .map(|call| (call.target, call.data.to_vec()))
.collect(); .collect();
// Construct the ContractCall for `aggregate` function to broadcast the transaction // Construct the ContractCall for `aggregate` function to broadcast the transaction

View File

@ -384,9 +384,12 @@ mod celo_tests {
assert_eq!(value, "initial value"); assert_eq!(value, "initial value");
// make a state mutating transaction // make a state mutating transaction
// gas estimation costs are sometimes under-reported on celo,
// so we manually set it to avoid failures
let call = contract let call = contract
.method::<_, H256>("setValue", "hi".to_owned()) .method::<_, H256>("setValue", "hi".to_owned())
.unwrap(); .unwrap()
.gas(100000);
let pending_tx = call.send().await.unwrap(); let pending_tx = call.send().await.unwrap();
let _receipt = pending_tx.await.unwrap(); let _receipt = pending_tx.await.unwrap();

View File

@ -26,10 +26,11 @@ tiny-keccak = { version = "2.0.2", default-features = false }
# misc # misc
serde = { version = "1.0.118", default-features = false, features = ["derive"] } serde = { version = "1.0.118", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.60", default-features = false } serde_json = { version = "1.0.61", default-features = false }
rustc-hex = { version = "2.1.0", default-features = false } thiserror = { version = "1.0.23", default-features = false }
thiserror = { version = "1.0.22", default-features = false }
glob = { version = "0.3.0", default-features = false } glob = { version = "0.3.0", default-features = false }
bytes = { version = "1.0.0", features = ["serde"] }
hex = { version = "0.4.2", default-features = false, features = ["std"] }
[dev-dependencies] [dev-dependencies]
ethers = { version = "0.1.3", path = "../ethers" } ethers = { version = "0.1.3", path = "../ethers" }

View File

@ -161,7 +161,7 @@ impl Tokenizable for Bytes {
} }
fn into_token(self) -> Token { fn into_token(self) -> Token {
Token::Bytes(self.0) Token::Bytes(self.to_vec())
} }
} }

View File

@ -1,33 +1,31 @@
use rustc_hex::{FromHex, ToHex};
use serde::de::{Error, Unexpected}; use serde::de::{Error, Unexpected};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Wrapper type around Vec<u8> to deserialize/serialize "0x" prefixed ethereum hex strings /// Wrapper type around Bytes to deserialize/serialize "0x" prefixed ethereum hex strings
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
pub struct Bytes( pub struct Bytes(
#[serde( #[serde(
serialize_with = "serialize_bytes", serialize_with = "serialize_bytes",
deserialize_with = "deserialize_bytes" deserialize_with = "deserialize_bytes"
)] )]
pub Vec<u8>, pub bytes::Bytes,
); );
impl AsRef<[u8]> for Bytes { impl Bytes {
fn as_ref(&self) -> &[u8] { pub fn to_vec(&self) -> Vec<u8> {
&self.0[..] self.as_ref().to_vec()
} }
} }
impl Bytes { impl AsRef<[u8]> for Bytes {
/// Returns an empty bytes vector fn as_ref(&self) -> &[u8] {
pub fn new() -> Self { &self.0.as_ref()
Bytes(vec![])
} }
} }
impl From<Vec<u8>> for Bytes { impl From<Vec<u8>> for Bytes {
fn from(src: Vec<u8>) -> Self { fn from(src: Vec<u8>) -> Self {
Self(src) Self(src.into())
} }
} }
@ -36,18 +34,18 @@ where
S: Serializer, S: Serializer,
T: AsRef<[u8]>, T: AsRef<[u8]>,
{ {
s.serialize_str(&format!("0x{}", x.as_ref().to_hex::<String>())) s.serialize_str(&format!("0x{}", hex::encode(x.as_ref())))
} }
pub fn deserialize_bytes<'de, D>(d: D) -> Result<Vec<u8>, D::Error> pub fn deserialize_bytes<'de, D>(d: D) -> Result<bytes::Bytes, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let value = String::deserialize(d)?; let value = String::deserialize(d)?;
if value.len() >= 2 && &value[0..2] == "0x" { if value.len() >= 2 && &value[0..2] == "0x" {
let bytes = FromHex::from_hex(&value[2..]) let bytes: Vec<u8> =
.map_err(|e| Error::custom(format!("Invalid hex: {}", e)))?; hex::decode(&value[2..]).map_err(|e| Error::custom(format!("Invalid hex: {}", e)))?;
Ok(bytes) Ok(bytes.into())
} else { } else {
Err(Error::invalid_value(Unexpected::Str(&value), &"0x prefix")) Err(Error::invalid_value(Unexpected::Str(&value), &"0x prefix"))
} }

View File

@ -4,7 +4,6 @@ use crate::{
utils::keccak256, utils::keccak256,
}; };
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use std::str::FromStr;
/// A log produced by a transaction. /// A log produced by a transaction.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -147,11 +146,6 @@ impl Filter {
self self
} }
pub fn address_str(mut self, address: &str) -> Result<Self, rustc_hex::FromHexError> {
self.address = Some(Address::from_str(address)?);
Ok(self)
}
/// given the event in string form, it hashes it and adds it to the topics to monitor /// given the event in string form, it hashes it and adds it to the topics to monitor
pub fn event(self, event_name: &str) -> Self { pub fn event(self, event_name: &str) -> Self {
let hash = H256::from(keccak256(event_name.as_bytes())); let hash = H256::from(keccak256(event_name.as_bytes()));
@ -259,7 +253,7 @@ mod tests {
let event = "ValueChanged(address,string,string)"; let event = "ValueChanged(address,string,string)";
let t0 = H256::from(keccak256(event.as_bytes())); let t0 = H256::from(keccak256(event.as_bytes()));
let addr = Address::from_str("f817796F60D268A36a57b8D2dF1B97B14C0D0E1d").unwrap(); let addr: Address = "f817796F60D268A36a57b8D2dF1B97B14C0D0E1d".parse().unwrap();
let filter = Filter::new(); let filter = Filter::new();
let ser = serialize(&filter.clone()); let ser = serialize(&filter.clone());

View File

@ -11,7 +11,7 @@ mod transaction;
pub use transaction::{Transaction, TransactionReceipt, TransactionRequest}; pub use transaction::{Transaction, TransactionReceipt, TransactionRequest};
mod bytes; mod bytes;
pub use bytes::Bytes; pub use self::bytes::Bytes;
mod block; mod block;
pub use block::{Block, BlockId, BlockNumber}; pub use block::{Block, BlockId, BlockNumber};

View File

@ -4,7 +4,6 @@ use crate::{
utils::hash_message, utils::hash_message,
}; };
use rustc_hex::{FromHex, ToHex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt, str::FromStr}; use std::{convert::TryFrom, fmt, str::FromStr};
@ -26,7 +25,7 @@ pub enum SignatureError {
InvalidLength(usize), InvalidLength(usize),
/// When parsing a signature from string to hex /// When parsing a signature from string to hex
#[error(transparent)] #[error(transparent)]
DecodingError(#[from] rustc_hex::FromHexError), DecodingError(#[from] hex::FromHexError),
/// Thrown when signature verification failed (i.e. when the address that /// Thrown when signature verification failed (i.e. when the address that
/// produced the signature did not match the expected address) /// produced the signature did not match the expected address)
#[error("Signature verification failed. Expected {0}, got {1}")] #[error("Signature verification failed. Expected {0}, got {1}")]
@ -66,7 +65,7 @@ pub struct Signature {
impl fmt::Display for Signature { impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sig = <[u8; 65]>::from(self); let sig = <[u8; 65]>::from(self);
write!(f, "{}", sig.to_hex::<String>()) write!(f, "{}", hex::encode(sig))
} }
} }
@ -174,7 +173,7 @@ impl FromStr for Signature {
type Err = SignatureError; type Err = SignatureError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes = s.from_hex::<Vec<u8>>()?; let bytes = hex::decode(s)?;
Signature::try_from(&bytes[..]) Signature::try_from(&bytes[..])
} }
} }

View File

@ -6,7 +6,6 @@ use crate::{
use rlp::RlpStream; use rlp::RlpStream;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr;
// Number of tx fields before signing // Number of tx fields before signing
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
@ -94,12 +93,6 @@ impl TransactionRequest {
self self
} }
/// Sets the `to` field in the transaction to the provided value
pub fn send_to_str(mut self, to: &str) -> Result<Self, rustc_hex::FromHexError> {
self.to = Some(Address::from_str(to)?.into());
Ok(self)
}
/// Sets the `to` field in the transaction to the provided value /// Sets the `to` field in the transaction to the provided value
pub fn to<T: Into<NameOrAddress>>(mut self, to: T) -> Self { pub fn to<T: Into<NameOrAddress>>(mut self, to: T) -> Self {
self.to = Some(to.into()); self.to = Some(to.into());
@ -196,7 +189,7 @@ impl TransactionRequest {
rlp_opt(rlp, self.to.as_ref()); rlp_opt(rlp, self.to.as_ref());
rlp_opt(rlp, self.value); rlp_opt(rlp, self.value);
rlp_opt(rlp, self.data.as_ref().map(|d| &d.0[..])); rlp_opt(rlp, self.data.as_ref().map(|d| d.as_ref()));
} }
} }
@ -328,7 +321,7 @@ impl Transaction {
} }
pub fn hash(&self) -> H256 { pub fn hash(&self) -> H256 {
keccak256(&self.rlp().0).into() keccak256(&self.rlp().as_ref()).into()
} }
pub fn rlp(&self) -> Bytes { pub fn rlp(&self) -> Bytes {
@ -343,7 +336,7 @@ impl Transaction {
rlp_opt(&mut rlp, self.to); rlp_opt(&mut rlp, self.to);
rlp.append(&self.value); rlp.append(&self.value);
rlp.append(&self.input.0); rlp.append(&self.input.as_ref());
rlp.append(&self.v); rlp.append(&self.v);
rlp.append(&self.r); rlp.append(&self.r);
rlp.append(&self.s); rlp.append(&self.s);

View File

@ -3,7 +3,6 @@ use crate::{
utils::{secret_key_to_address, unused_port}, utils::{secret_key_to_address, unused_port},
}; };
use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey}; use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey};
use rustc_hex::FromHex;
use std::{ use std::{
io::{BufRead, BufReader}, io::{BufRead, BufReader},
process::{Child, Command}, process::{Child, Command},
@ -161,9 +160,7 @@ impl Ganache {
if is_private_key && line.starts_with('(') { if is_private_key && line.starts_with('(') {
let key_str = &line[6..line.len() - 1]; let key_str = &line[6..line.len() - 1];
let key_hex = key_str let key_hex = hex::decode(key_str).expect("could not parse as hex");
.from_hex::<Vec<u8>>()
.expect("could not parse as hex");
let key = K256SecretKey::from_bytes(&key_hex).expect("did not get private key"); let key = K256SecretKey::from_bytes(&key_hex).expect("did not get private key");
addresses.push(secret_key_to_address(&SigningKey::from(&key))); addresses.push(secret_key_to_address(&SigningKey::from(&key)));
private_keys.push(key); private_keys.push(key);

View File

@ -59,13 +59,12 @@ pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use rustc_hex::ToHex;
#[test] #[test]
// from https://emn178.github.io/online-tools/keccak_256.html // from https://emn178.github.io/online-tools/keccak_256.html
fn test_keccak256() { fn test_keccak256() {
assert_eq!( assert_eq!(
keccak256(b"hello").to_hex::<String>(), hex::encode(keccak256(b"hello")),
"1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8" "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
); );
} }

View File

@ -25,7 +25,6 @@ pub use rlp;
use crate::types::{Address, Bytes, U256}; use crate::types::{Address, Bytes, U256};
use k256::{ecdsa::SigningKey, EncodedPoint as K256PublicKey}; use k256::{ecdsa::SigningKey, EncodedPoint as K256PublicKey};
use rustc_hex::ToHex;
use std::convert::TryInto; use std::convert::TryInto;
/// 1 Ether = 1e18 Wei == 0x0de0b6b3a7640000 Wei /// 1 Ether = 1e18 Wei == 0x0de0b6b3a7640000 Wei
@ -125,10 +124,10 @@ pub fn to_checksum(addr: &Address, chain_id: Option<u8>) -> String {
Some(chain_id) => format!("{}0x{:x}", chain_id, addr), Some(chain_id) => format!("{}0x{:x}", chain_id, addr),
None => format!("{:x}", addr), None => format!("{:x}", addr),
}; };
let hash = keccak256(&prefixed_addr).to_hex::<String>(); let hash = hex::encode(keccak256(&prefixed_addr));
let hash = hash.as_bytes(); let hash = hash.as_bytes();
let addr_hex = addr.as_bytes().to_hex::<String>(); let addr_hex = hex::encode(addr.as_bytes());
let addr_hex = addr_hex.as_bytes(); let addr_hex = addr_hex.as_bytes();
addr_hex addr_hex
@ -161,7 +160,6 @@ pub(crate) fn unused_port() -> u16 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use rustc_hex::FromHex;
#[test] #[test]
fn wei_in_ether() { fn wei_in_ether() {
@ -324,8 +322,8 @@ mod tests {
), ),
] { ] {
let from = from.parse::<Address>().unwrap(); let from = from.parse::<Address>().unwrap();
let salt = salt.from_hex::<Vec<u8>>().unwrap(); let salt = hex::decode(salt).unwrap();
let init_code = init_code.from_hex::<Vec<u8>>().unwrap(); let init_code = hex::decode(init_code).unwrap();
let expected = expected.parse::<Address>().unwrap(); let expected = expected.parse::<Address>().unwrap();
assert_eq!(expected, get_create2_address(from, salt, init_code)) assert_eq!(expected, get_create2_address(from, salt, init_code))
} }

View File

@ -1,6 +1,5 @@
use crate::{abi::Abi, types::Bytes}; use crate::{abi::Abi, types::Bytes};
use glob::glob; use glob::glob;
use rustc_hex::FromHex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt, io::BufRead, path::PathBuf, process::Command}; use std::{collections::HashMap, fmt, io::BufRead, path::PathBuf, process::Command};
use thiserror::Error; use thiserror::Error;
@ -145,9 +144,7 @@ impl Solc {
.expect("could not parse `solc` abi, this should never happen"); .expect("could not parse `solc` abi, this should never happen");
// parse the bytecode // parse the bytecode
let bytecode = contract let bytecode = hex::decode(contract.bin)
.bin
.from_hex::<Vec<u8>>()
.expect("solc did not produce valid bytecode") .expect("solc did not produce valid bytecode")
.into(); .into();
(name, CompiledContract { abi, bytecode }) (name, CompiledContract { abi, bytecode })

View File

@ -30,15 +30,13 @@ serde-aux = { version = "2.1.0", default-features = false }
reqwest = { version = "0.10.10", default-features = false, features = ["json", "rustls-tls"] } reqwest = { version = "0.10.10", default-features = false, features = ["json", "rustls-tls"] }
url = { version = "2.2.0", default-features = false } url = { version = "2.2.0", default-features = false }
# optional for runtime tokio = { version = "1.0" }
tokio = { version = "0.2.22", optional = true }
async-std = { version = "1.6.5", optional = true }
[dev-dependencies] [dev-dependencies]
ethers = { version = "0.1.3", path = "../ethers" } ethers = { version = "0.1.3", path = "../ethers" }
futures-executor = { version = "0.3.5", features = ["thread-pool"] } futures-executor = { version = "0.3.5", features = ["thread-pool"] }
rustc-hex = "2.1.0" hex = { version = "0.4.2", default-features = false, features = ["std"] }
tokio = { version = "0.2.21", default-features = false, features = ["rt-core", "macros"] } tokio = { version = "1.0", default-features = false, features = ["rt", "macros", "time"] }
[features] [features]
celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo"] celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo"]

View File

@ -12,18 +12,8 @@ use std::sync::Arc;
use std::{pin::Pin, time::Instant}; use std::{pin::Pin, time::Instant};
use thiserror::Error; use thiserror::Error;
#[cfg(any(feature = "async-std", feature = "tokio"))]
use tracing_futures::Instrument;
#[cfg(all(not(feature = "tokio"), feature = "async-std"))]
use async_std::task::spawn;
#[cfg(all(feature = "tokio", not(feature = "async-std")))]
use tokio::spawn; use tokio::spawn;
#[cfg(all(feature = "tokio", all(feature = "async-std")))] use tracing_futures::Instrument;
// this should never happen, used to silence clippy warnings
fn spawn<T>(_: T) {
unimplemented!("do not use both tokio and async-std!")
}
/// Trait for fetching updated gas prices after a transaction has been first /// Trait for fetching updated gas prices after a transaction has been first
/// broadcast /// broadcast
@ -46,10 +36,6 @@ pub enum Frequency {
/// A Gas escalator allows bumping transactions' gas price to avoid getting them /// A Gas escalator allows bumping transactions' gas price to avoid getting them
/// stuck in the memory pool. /// stuck in the memory pool.
/// ///
/// If the crate is compiled with the `tokio` or `async-std` features, it will
/// automatically start bumping transactions in the background. Otherwise, you need
/// to spawn the `escalate` call yourself with an executor of choice.
///
/// ```no_run /// ```no_run
/// use ethers::{ /// use ethers::{
/// providers::{Provider, Http}, /// providers::{Provider, Http},
@ -135,7 +121,6 @@ where
txs: Arc::new(Mutex::new(Vec::new())), txs: Arc::new(Mutex::new(Vec::new())),
}; };
#[cfg(any(feature = "async-std", feature = "tokio"))]
{ {
let this2 = this.clone(); let this2 = this.clone();
spawn(async move { spawn(async move {

View File

@ -135,7 +135,7 @@ where
// Get the actual transaction hash // Get the actual transaction hash
let rlp = tx.rlp_signed(&signature); let rlp = tx.rlp_signed(&signature);
let hash = keccak256(&rlp.0); let hash = keccak256(&rlp.as_ref());
// This function should not be called with ENS names // This function should not be called with ENS names
let to = tx.to.map(|to| match to { let to = tx.to.map(|to| match to {
@ -298,7 +298,6 @@ where
mod tests { mod tests {
use super::*; use super::*;
use ethers::{providers::Provider, signers::LocalWallet}; use ethers::{providers::Provider, signers::LocalWallet};
use rustc_hex::FromHex;
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::test] #[tokio::test]
@ -337,7 +336,7 @@ mod tests {
.unwrap() .unwrap()
); );
let expected_rlp = Bytes("f869808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a0c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895a0727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68".from_hex().unwrap()); let expected_rlp = Bytes::from(hex::decode("f869808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a0c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895a0727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68").unwrap());
assert_eq!(tx.rlp(), expected_rlp); assert_eq!(tx.rlp(), expected_rlp);
} }
} }

View File

@ -43,7 +43,7 @@ async fn gas_escalator_live() {
.unwrap(); .unwrap();
// Wait a bunch of seconds and refresh etherscan to see the transactions get bumped // Wait a bunch of seconds and refresh etherscan to see the transactions get bumped
tokio::time::delay_for(std::time::Duration::from_secs(100)).await; tokio::time::sleep(std::time::Duration::from_secs(100)).await;
// TODO: Figure out how to test this behavior properly in a local network. If the gas price was bumped // TODO: Figure out how to test this behavior properly in a local network. If the gas price was bumped
// then the tx hash will be different // then the tx hash will be different

View File

@ -35,47 +35,16 @@ pin-project = { version = "1.0.2", default-features = false }
tracing = { version = "0.1.22", default-features = false } tracing = { version = "0.1.22", default-features = false }
tracing-futures = { version = "0.2.4", default-features = false } tracing-futures = { version = "0.2.4", default-features = false }
# ws support async-std and tokio runtimes for the convenience methods # tokio
async-tungstenite = { version = "0.6.0", default-features = false, optional = true } tokio = { version = "1.0", default-features = false, optional = true }
async-std = { version = "1.6.2", default-features = false, optional = true } tokio-tungstenite = { version = "0.12.0", default-features = false, features = ["connect", "tls"], optional = true }
tokio = { version = "0.2.21", default-features = false, optional = true }
# needed for tls
real-tokio-native-tls = { package = "tokio-native-tls", version = "0.1.0", default-features = false, optional = true }
async-tls = { version = "0.7.0", optional = true }
[dev-dependencies] [dev-dependencies]
ethers = { version = "0.1.3", path = "../ethers" } ethers = { version = "0.1.3", path = "../ethers" }
tokio = { version = "1.0", default-features = false, features = ["rt", "macros"] }
rustc-hex = "2.1.0" hex = { version = "0.4.2", default-features = false, features = ["std"] }
tokio = { version = "0.2.21", default-features = false, features = ["rt-core", "macros"] }
async-std = { version = "1.6.2", default-features = false, features = ["attributes"] }
async-tungstenite = { version = "0.6.0", default-features = false, features = ["tokio-runtime"] }
[features] [features]
# slightly opinionated, but for convenience we default to tokio-tls default = ["ws"]
# to allow websockets w/ TLS support
default = ["tokio-tls"]
celo = ["ethers-core/celo"] celo = ["ethers-core/celo"]
ws = ["async-tungstenite"] ws = ["tokio", "tokio-tungstenite"]
tokio-runtime = [
"ws",
"tokio",
"async-tungstenite/tokio-runtime"
]
tokio-tls = [
"tokio-runtime",
"async-tungstenite/tokio-native-tls",
"real-tokio-native-tls"
]
async-std-runtime = [
"ws",
"async-std",
"async-tungstenite/async-std-runtime"
]
async-std-tls = [
"async-std-runtime",
"async-tungstenite/async-tls",
"async-tls"
]

View File

@ -69,7 +69,6 @@ pub fn namehash(name: &str) -> H256 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use rustc_hex::FromHex;
fn assert_hex(hash: H256, val: &str) { fn assert_hex(hash: H256, val: &str) {
let v = if val.starts_with("0x") { let v = if val.starts_with("0x") {
@ -78,14 +77,11 @@ mod tests {
val val
}; };
assert_eq!(hash.0.to_vec(), v.from_hex::<Vec<u8>>().unwrap()); assert_eq!(hash.0.to_vec(), hex::decode(v).unwrap());
} }
#[test] #[test]
fn test_namehash() { fn test_namehash() {
dbg!("00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
.from_hex::<Vec<u8>>()
.unwrap());
for (name, expected) in &[ for (name, expected) in &[
( (
"", "",

View File

@ -30,28 +30,9 @@
//! //!
//! # Websockets //! # Websockets
//! //!
//! The crate has support for WebSockets. If none of the provided async runtime //! The crate has support for WebSockets via Tokio.
//! features are enabled, you must manually instantiate the WS connection and wrap
//! it with with a [`Ws::new`](method@crate::Ws::new) call.
//! //!
//! ```ignore
//! use ethers::providers::Ws;
//!
//! let ws = Ws::new(...);
//! ``` //! ```
//!
//! If you have compiled the library with any of the following features, you may
//! instantiate the websocket instance with the `connect` call and your URL:
//! - `tokio-runtime`: Uses `tokio` as the runtime
//! - `async-std-runtime`: Uses `async-std-runtime`
//!
//! ```no_run
//! # #[cfg(any(
//! # feature = "tokio-runtime",
//! # feature = "tokio-tls",
//! # feature = "async-std-runtime",
//! # feature = "async-std-tls",
//! # ))]
//! # async fn foo() -> Result<(), Box<dyn std::error::Error>> { //! # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
//! # use ethers::providers::Ws; //! # use ethers::providers::Ws;
//! let ws = Ws::connect("ws://localhost:8545").await?; //! let ws = Ws::connect("ws://localhost:8545").await?;
@ -59,24 +40,6 @@
//! # } //! # }
//! ``` //! ```
//! //!
//! TLS support is also provided via the following feature flags:
//! - `tokio-tls`
//! - `async-tls`
//!
//! ```no_run
//! # #[cfg(any(
//! # feature = "tokio-runtime",
//! # feature = "tokio-tls",
//! # feature = "async-std-runtime",
//! # feature = "async-std-tls",
//! # ))]
//! # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
//! # use ethers::providers::Ws;
//! let ws = Ws::connect("wss://localhost:8545").await?;
//! # Ok(())
//! # }
//! ```
//!
//! # Ethereum Name Service //! # Ethereum Name Service
//! //!
//! The provider may also be used to resolve [Ethereum Name Service](https://ens.domains) (ENS) names //! The provider may also be used to resolve [Ethereum Name Service](https://ens.domains) (ENS) names

View File

@ -685,11 +685,11 @@ impl<P: JsonRpcClient> Provider<P> {
} }
} }
#[cfg(any(feature = "tokio-runtime", feature = "async-std-runtime"))] #[cfg(feature = "ws")]
impl Provider<crate::Ws> { impl Provider<crate::Ws> {
/// Direct connection to a websocket endpoint /// Direct connection to a websocket endpoint
pub async fn connect( pub async fn connect(
url: impl async_tungstenite::tungstenite::client::IntoClientRequest + Unpin, url: impl tokio_tungstenite::tungstenite::client::IntoClientRequest + Unpin,
) -> Result<Self, ProviderError> { ) -> Result<Self, ProviderError> {
let ws = crate::Ws::connect(url).await?; let ws = crate::Ws::connect(url).await?;
Ok(Self::new(ws)) Ok(Self::new(ws))
@ -730,8 +730,8 @@ impl Provider<MockProvider> {
/// ///
/// If the provided bytes were not an interpretation of an address /// If the provided bytes were not an interpretation of an address
fn decode_bytes<T: Detokenize>(param: ParamType, bytes: Bytes) -> T { fn decode_bytes<T: Detokenize>(param: ParamType, bytes: Bytes) -> T {
let tokens = let tokens = abi::decode(&[param], &bytes.as_ref())
abi::decode(&[param], &bytes.0).expect("could not abi-decode bytes to address tokens"); .expect("could not abi-decode bytes to address tokens");
T::from_tokens(tokens).expect("could not parse tokens as address") T::from_tokens(tokens).expect("could not parse tokens as address")
} }

View File

@ -84,7 +84,7 @@ where
} }
#[pinned_drop] #[pinned_drop]
impl<'a, P, R> PinnedDrop for SubscriptionStream<'a, P, R> impl<P, R> PinnedDrop for SubscriptionStream<'_, P, R>
where where
P: PubsubClient, P: PubsubClient,
R: DeserializeOwned, R: DeserializeOwned,

View File

@ -6,7 +6,6 @@ use crate::{
use ethers_core::types::U256; use ethers_core::types::U256;
use async_trait::async_trait; use async_trait::async_trait;
use async_tungstenite::tungstenite::{self, protocol::Message};
use futures_channel::{mpsc, oneshot}; use futures_channel::{mpsc, oneshot};
use futures_util::{ use futures_util::{
sink::{Sink, SinkExt}, sink::{Sink, SinkExt},
@ -22,53 +21,21 @@ use std::{
}, },
}; };
use thiserror::Error; use thiserror::Error;
use tokio_tungstenite::{
// `connect_async` adapter connect_async,
#[cfg(all(feature = "async-std-runtime", not(feature = "tokio-runtime")))] tungstenite::{self, protocol::Message},
use async_tungstenite::async_std::connect_async; };
#[cfg(feature = "tokio-runtime")]
use async_tungstenite::tokio::connect_async;
/// A JSON-RPC Client over Websockets. /// A JSON-RPC Client over Websockets.
/// ///
/// If the library is not compiled with any runtime support, then you will have
/// to manually instantiate a websocket connection and call `Provider::new` on it.
///
/// ```ignore
/// use ethers::providers::Ws;
///
/// let ws = Ws::new(...)
/// ```
///
/// If you have compiled the library with any of the following features, you may
/// instantiate the websocket instance with the `connect` call and your URL:
/// - `tokio-runtime`: Uses `tokio` as the runtime
/// - `tokio-tls`: Same as `tokio-runtime` but with TLS support
/// - `async-std-runtime`: Uses `async-std-runtime`
/// - `async-tls`: Same as `async-std-runtime` but with TLS support
///
/// ```no_run /// ```no_run
/// # #[cfg(any(
/// # feature = "tokio-runtime",
/// # feature = "tokio-tls",
/// # feature = "async-std-runtime",
/// # feature = "async-std-tls",
/// # ))]
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> { /// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// use ethers::providers::Ws; /// use ethers::providers::Ws;
/// ///
/// let ws = Ws::connect("ws://localhost:8545").await?;
///
/// // If built with TLS support (otherwise will get a "TLS Support not compiled in" error)
/// let ws = Ws::connect("wss://localhost:8545").await?; /// let ws = Ws::connect("wss://localhost:8545").await?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
///
/// This feature is built using [`async-tungstenite`](https://docs.rs/async-tungstenite). If you need other runtimes,
/// consider importing `async-tungstenite` with the [corresponding feature
/// flag](https://github.com/sdroege/async-tungstenite/blob/master/Cargo.toml#L15-L22)
/// for your runtime.
#[derive(Clone)] #[derive(Clone)]
pub struct Ws { pub struct Ws {
id: Arc<AtomicU64>, id: Arc<AtomicU64>,
@ -123,8 +90,7 @@ impl Ws {
} }
} }
/// Initializes a new WebSocket Client, assuming usage of tokio or async-std /// Initializes a new WebSocket Client
#[cfg(any(feature = "tokio-runtime", feature = "async-std-runtime"))]
pub async fn connect( pub async fn connect(
url: impl tungstenite::client::IntoClientRequest + Unpin, url: impl tungstenite::client::IntoClientRequest + Unpin,
) -> Result<Self, ClientError> { ) -> Result<Self, ClientError> {
@ -214,7 +180,6 @@ where
} }
/// Spawns the event loop /// Spawns the event loop
#[allow(unused)]
fn spawn(mut self) fn spawn(mut self)
where where
S: 'static, S: 'static,
@ -225,12 +190,7 @@ where
} }
}; };
#[cfg(all(not(feature = "async-std-runtime"), feature = "tokio-runtime"))]
tokio::spawn(f); tokio::spawn(f);
// TODO: Ensure that this works with both async-std and tokio.
// Remove allow(unused) when fixed.
#[cfg(all(feature = "async-std-runtime", not(feature = "tokio-runtime")))]
async_std::task::spawn(f);
} }
/// Processes 1 item selected from the incoming `requests` or `ws` /// Processes 1 item selected from the incoming `requests` or `ws`

View File

@ -41,30 +41,17 @@ mod eth_tests {
} }
// Without TLS this would error with "TLS Support not compiled in" // Without TLS this would error with "TLS Support not compiled in"
#[test] #[tokio::test]
#[cfg(any(feature = "async-std-tls", feature = "tokio-tls"))] async fn ssl_websocket() {
fn ssl_websocket() {
// this is extremely ugly but I couldn't figure out a better way of having
// a shared async test for both runtimes
#[cfg(feature = "async-std-tls")]
let block_on = async_std::task::block_on;
#[cfg(feature = "tokio-tls")]
let mut runtime = tokio::runtime::Runtime::new().unwrap();
#[cfg(feature = "tokio-tls")]
let mut block_on = |x| runtime.block_on(x);
use ethers::providers::Ws; use ethers::providers::Ws;
block_on(async move { let ws = Ws::connect("wss://rinkeby.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27")
let ws = Ws::connect("wss://rinkeby.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27") .await
.await .unwrap();
.unwrap(); let provider = Provider::new(ws);
let provider = Provider::new(ws); let _number = provider.get_block_number().await.unwrap();
let _number = provider.get_block_number().await.unwrap();
});
} }
#[tokio::test] #[tokio::test]
#[cfg(feature = "tokio-runtime")]
async fn watch_blocks_websocket() { async fn watch_blocks_websocket() {
use ethers::{ use ethers::{
providers::{StreamExt, Ws}, providers::{StreamExt, Ws},
@ -72,7 +59,7 @@ mod eth_tests {
}; };
let ganache = Ganache::new().block_time(2u64).spawn(); let ganache = Ganache::new().block_time(2u64).spawn();
let (ws, _) = async_tungstenite::tokio::connect_async(ganache.ws_endpoint()) let (ws, _) = tokio_tungstenite::connect_async(ganache.ws_endpoint())
.await .await
.unwrap(); .unwrap();
let provider = Provider::new(Ws::new(ws)).interval(Duration::from_millis(500u64)); let provider = Provider::new(Ws::new(ws)).interval(Duration::from_millis(500u64));
@ -149,7 +136,6 @@ mod celo_tests {
use super::*; use super::*;
use ethers::types::{Randomness, H256}; use ethers::types::{Randomness, H256};
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use rustc_hex::FromHex;
#[tokio::test] #[tokio::test]
// https://alfajores-blockscout.celo-testnet.org/tx/0x544ea96cddb16aeeaedaf90885c1e02be4905f3eb43d6db3f28cac4dbe76a625/internal_transactions // https://alfajores-blockscout.celo-testnet.org/tx/0x544ea96cddb16aeeaedaf90885c1e02be4905f3eb43d6db3f28cac4dbe76a625/internal_transactions
@ -176,14 +162,16 @@ mod celo_tests {
assert_eq!( assert_eq!(
block.randomness, block.randomness,
Randomness { Randomness {
committed: "003e12deb86292844274493e9ab6e57ed1e276202c16799d97af723eb0d3253f" committed: hex::decode(
.from_hex::<Vec<u8>>() "003e12deb86292844274493e9ab6e57ed1e276202c16799d97af723eb0d3253f"
.unwrap() )
.into(), .unwrap()
revealed: "1333b3b45e0385da48a01b4459aeda7607867ef6a41167cfdeefa49b9fdce6d7" .into(),
.from_hex::<Vec<u8>>() revealed: hex::decode(
.unwrap() "1333b3b45e0385da48a01b4459aeda7607867ef6a41167cfdeefa49b9fdce6d7"
.into(), )
.unwrap()
.into(),
} }
); );
} }

View File

@ -16,23 +16,23 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies] [dependencies]
ethers-core = { version = "0.1.3", path = "../ethers-core" } ethers-core = { version = "0.1.3", path = "../ethers-core" }
thiserror = { version = "1.0.22", default-features = false } thiserror = { version = "1.0.22", default-features = false }
futures-util = { version = "0.3.8", default-features = false }
futures-executor = { version = "0.3.8", default-features = false }
serde = { version = "1.0.118", default-features = false } serde = { version = "1.0.118", default-features = false }
coins-ledger = { git = "https://github.com/summa-tx/bitcoins-rs", default-features = false, optional = true, branch = "master" } coins-ledger = { git = "https://github.com/summa-tx/bitcoins-rs", default-features = false, optional = true, branch = "master" }
rustc-hex = { version = "2.1.0", default-features = false } hex = { version = "0.4.2", default-features = false, features = ["std"] }
async-trait = { version = "0.1.40", default-features = false } async-trait = { version = "0.1.40", default-features = false }
elliptic-curve = { version = "0.8.4", default-features = false } elliptic-curve = { version = "0.8.4", default-features = false }
sha2 = { version = "0.9.2", default-features = false } sha2 = { version = "0.9.2", default-features = false }
rand = { version = "0.7.3", default-features = false } rand = { version = "0.7.3", default-features = false }
yubihsm = { version = "0.37.0", features = ["secp256k1", "http", "usb"], optional = true } yubihsm = { version = "0.37.0", features = ["secp256k1", "http", "usb"], optional = true }
futures-util = "0.3.8"
futures-executor = "0.3.8"
[dev-dependencies] [dev-dependencies]
ethers = { version = "0.1.3", path = "../ethers" } ethers = { version = "0.1.3", path = "../ethers" }
yubihsm = { version = "0.37.0", features = ["secp256k1", "usb", "mockhsm"] } yubihsm = { version = "0.37.0", features = ["secp256k1", "usb", "mockhsm"] }
tokio = { version = "0.2.21", default-features = false, features = ["macros"] } tokio = { version = "1.0", default-features = false, features = ["macros"] }
serde_json = { version = "1.0.55", default-features = false } serde_json = { version = "1.0.55", default-features = false }
[features] [features]

View File

@ -95,8 +95,10 @@ impl LedgerEthereum {
let address = { let address = {
// extract the address from the response // extract the address from the response
let offset = 1 + result[0] as usize; let offset = 1 + result[0] as usize;
let address = &result[offset + 1..offset + 1 + result[offset] as usize]; let address_str = &result[offset + 1..offset + 1 + result[offset] as usize];
std::str::from_utf8(address)?.parse::<Address>()? let mut address = [0; 20];
address.copy_from_slice(&hex::decode(address_str)?);
Address::from(address)
}; };
Ok(address) Ok(address)
@ -207,7 +209,6 @@ mod tests {
use super::*; use super::*;
use crate::Signer; use crate::Signer;
use ethers::prelude::*; use ethers::prelude::*;
use rustc_hex::FromHex;
use std::str::FromStr; use std::str::FromStr;
#[tokio::test] #[tokio::test]
@ -239,11 +240,12 @@ mod tests {
.unwrap(); .unwrap();
// approve uni v2 router 0xff // approve uni v2 router 0xff
let data = "095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".from_hex::<Vec<u8>>().unwrap(); let data = hex::decode("095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
let tx_req = TransactionRequest::new() let tx_req = TransactionRequest::new()
.send_to_str("2ed7afa17473e17ac59908f088b4371d28585476") .to("2ed7afa17473e17ac59908f088b4371d28585476"
.unwrap() .parse::<Address>()
.unwrap())
.gas(1000000) .gas(1000000)
.gas_price(400e9 as u64) .gas_price(400e9 as u64)
.nonce(5) .nonce(5)

View File

@ -34,7 +34,7 @@ pub enum LedgerError {
UnexpectedNullResponse, UnexpectedNullResponse,
#[error(transparent)] #[error(transparent)]
HexError(#[from] rustc_hex::FromHexError), HexError(#[from] hex::FromHexError),
#[error("Error when decoding UTF8 Response: {0}")] #[error("Error when decoding UTF8 Response: {0}")]
Utf8Error(#[from] std::str::Utf8Error), Utf8Error(#[from] std::str::Utf8Error),

View File

@ -9,7 +9,6 @@ use ethers_core::{
types::Address, types::Address,
utils::keccak256, utils::keccak256,
}; };
use rustc_hex::FromHex;
use std::str::FromStr; use std::str::FromStr;
impl Clone for Wallet<SigningKey> { impl Clone for Wallet<SigningKey> {
@ -87,9 +86,7 @@ impl FromStr for Wallet<SigningKey> {
type Err = K256Error; type Err = K256Error;
fn from_str(src: &str) -> Result<Self, Self::Err> { fn from_str(src: &str) -> Result<Self, Self::Err> {
let src = src let src = hex::decode(src).expect("invalid hex when reading PrivateKey");
.from_hex::<Vec<u8>>()
.expect("invalid hex when reading PrivateKey");
let sk = SigningKey::from_bytes(&src).unwrap(); // TODO let sk = SigningKey::from_bytes(&src).unwrap(); // TODO
Ok(sk.into()) Ok(sk.into())
} }

View File

@ -67,13 +67,11 @@ impl From<YubiSigner<Secp256k1>> for Wallet<YubiSigner<Secp256k1>> {
mod tests { mod tests {
use super::*; use super::*;
use crate::Signer; use crate::Signer;
use rustc_hex::FromHex;
use std::str::FromStr; use std::str::FromStr;
#[tokio::test] #[tokio::test]
async fn from_key() { async fn from_key() {
let key = "2d8c44dc2dd2f0bea410e342885379192381e82d855b1b112f9b55544f1e0900" let key = hex::decode("2d8c44dc2dd2f0bea410e342885379192381e82d855b1b112f9b55544f1e0900")
.from_hex::<Vec<u8>>()
.unwrap(); .unwrap();
let connector = yubihsm::Connector::mockhsm(); let connector = yubihsm::Connector::mockhsm();

View File

@ -20,16 +20,6 @@ rustdoc-args = ["--cfg", "docsrs"]
features = ["full"] features = ["full"]
[features] [features]
abigen = ["contract", "ethers-contract/abigen"]
default = ["full"]
full = [
"contract",
"providers",
"signers",
"core",
"middleware",
]
celo = [ celo = [
"ethers-core/celo", "ethers-core/celo",
"ethers-providers/celo", "ethers-providers/celo",
@ -38,27 +28,23 @@ celo = [
"ethers-middleware/celo", "ethers-middleware/celo",
] ]
core = ["ethers-core"]
contract = ["ethers-contract"]
providers = ["ethers-providers"]
middleware = ["ethers-middleware"]
signers = ["ethers-signers"]
ledger = ["ethers-signers/ledger"] ledger = ["ethers-signers/ledger"]
yubi = ["ethers-signers/yubi"] yubi = ["ethers-signers/yubi"]
ws = ["ethers-providers/ws"]
abigen = ["ethers-contract/abigen"]
[dependencies] [dependencies]
ethers-contract = { version = "0.1.3", path = "../ethers-contract", optional = true } ethers-contract = { version = "0.1.3", path = "../ethers-contract" }
ethers-core = { version = "0.1.3", path = "../ethers-core", optional = true } ethers-core = { version = "0.1.3", path = "../ethers-core" }
ethers-providers = { version = "0.1.3", path = "../ethers-providers", optional = true } ethers-providers = { version = "0.1.3", path = "../ethers-providers" }
ethers-signers = { version = "0.1.3", path = "../ethers-signers", optional = true } ethers-signers = { version = "0.1.3", path = "../ethers-signers" }
ethers-middleware = { version = "0.1.3", path = "../ethers-middleware", optional = true } ethers-middleware = { version = "0.1.3", path = "../ethers-middleware" }
[dev-dependencies] [dev-dependencies]
ethers-contract = { version = "0.1.3", path = "../ethers-contract", features = ["abigen"] } ethers-contract = { version = "0.1.3", path = "../ethers-contract", features = ["abigen"] }
ethers-providers = { version = "0.1.3", path = "../ethers-providers" }
anyhow = "1.0.31" anyhow = "1.0.36"
rand = "0.7" rand = "0.7"
serde = { version = "1.0.110", features = ["derive"] } serde = { version = "1.0.110", features = ["derive"] }
serde_json = "1.0.53" serde_json = "1.0.53"
tokio = { version = "0.2.21", features = ["macros"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }

View File

@ -82,50 +82,28 @@
//! [`utils`]: core::utils //! [`utils`]: core::utils
//! [`abi`]: core::abi //! [`abi`]: core::abi
//! [`types`]: core::types //! [`types`]: core::types
#[cfg(feature = "contract")]
pub use ethers_contract as contract; pub use ethers_contract as contract;
#[cfg(feature = "providers")]
pub use ethers_providers as providers;
#[cfg(feature = "signers")]
pub use ethers_signers as signers;
#[cfg(feature = "core")]
pub use ethers_core as core; pub use ethers_core as core;
#[cfg(feature = "middleware")]
pub use ethers_middleware as middleware; pub use ethers_middleware as middleware;
pub use ethers_providers as providers;
pub use ethers_signers as signers;
// Re-export ethers_core::utils/types/abi // Re-export ethers_core::utils/types/abi
// We hide these docs so that the rustdoc links send the visitor // We hide these docs so that the rustdoc links send the visitor
// to the corresponding crate, instead of the re-export // to the corresponding crate, instead of the re-export
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "core")]
pub use ethers_core::abi; pub use ethers_core::abi;
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "core")]
pub use ethers_core::types; pub use ethers_core::types;
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "core")]
pub use ethers_core::utils; pub use ethers_core::utils;
/// Easy imports of frequently used type definitions and traits /// Easy imports of frequently used type definitions and traits
#[doc(hidden)] #[doc(hidden)]
pub mod prelude { pub mod prelude {
#[cfg(feature = "contract")]
pub use ethers_contract::*; pub use ethers_contract::*;
#[cfg(feature = "providers")]
pub use ethers_providers::*;
#[cfg(feature = "signers")]
pub use ethers_signers::*;
#[cfg(feature = "middleware")]
pub use ethers_middleware::*;
#[cfg(feature = "core")]
pub use ethers_core::types::*; pub use ethers_core::types::*;
pub use ethers_middleware::*;
pub use ethers_providers::*;
pub use ethers_signers::*;
} }