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:
parent
7eec705cec
commit
5c1f8f532a
|
@ -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
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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" }
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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! {
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(), ¶ms)?)
|
.encode_input(self.bytecode.to_vec(), ¶ms)?
|
||||||
}
|
.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`
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 Bytes {
|
||||||
|
pub fn to_vec(&self) -> Vec<u8> {
|
||||||
|
self.as_ref().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for Bytes {
|
impl AsRef<[u8]> for Bytes {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.0[..]
|
&self.0.as_ref()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bytes {
|
|
||||||
/// Returns an empty bytes vector
|
|
||||||
pub fn new() -> Self {
|
|
||||||
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"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 })
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
|
||||||
]
|
|
||||||
|
|
|
@ -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 &[
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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,12 +162,14 @@ mod celo_tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
block.randomness,
|
block.randomness,
|
||||||
Randomness {
|
Randomness {
|
||||||
committed: "003e12deb86292844274493e9ab6e57ed1e276202c16799d97af723eb0d3253f"
|
committed: hex::decode(
|
||||||
.from_hex::<Vec<u8>>()
|
"003e12deb86292844274493e9ab6e57ed1e276202c16799d97af723eb0d3253f"
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into(),
|
.into(),
|
||||||
revealed: "1333b3b45e0385da48a01b4459aeda7607867ef6a41167cfdeefa49b9fdce6d7"
|
revealed: hex::decode(
|
||||||
.from_hex::<Vec<u8>>()
|
"1333b3b45e0385da48a01b4459aeda7607867ef6a41167cfdeefa49b9fdce6d7"
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
|
@ -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::*;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue