diff --git a/Cargo.lock b/Cargo.lock index d6f87473..68c445a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,14 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation" version = "0.7.0" @@ -158,6 +166,15 @@ dependencies = [ "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethers-signers" +version = "0.1.0" +dependencies = [ + "ethers-providers 0.1.0", + "ethers-types 0.1.0", + "ethers-utils 0.1.0", +] + [[package]] name = "ethers-types" version = "0.1.0" @@ -169,6 +186,7 @@ dependencies = [ "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "secp256k1 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -199,6 +217,11 @@ name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -617,7 +640,11 @@ name = "rand" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1267,6 +1294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" "checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" "checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" "checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" @@ -1278,6 +1306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ethereum-types 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "473aecff686bd8e7b9db0165cbbb53562376b39bf35b427f0c60446a9e1634b0" "checksum fixed-hash 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11498d382790b7a8f2fd211780bec78619bba81cdad3a283997c0c41f836759c" "checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" diff --git a/Cargo.toml b/Cargo.toml index 96635a66..dd491b15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ # "./crates/ethers-contract", # "./crates/ethers-derive", "./crates/ethers-providers", - # "./crates/ethers-signers", + "./crates/ethers-signers", "./crates/ethers-types", "./crates/ethers-utils", ] diff --git a/crates/ethers-providers/src/http.rs b/crates/ethers-providers/src/http.rs index d0576fb9..63aa0eb1 100644 --- a/crates/ethers-providers/src/http.rs +++ b/crates/ethers-providers/src/http.rs @@ -7,12 +7,11 @@ use reqwest::{Client, Error as ReqwestError}; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::{ - convert::TryFrom, fmt, sync::atomic::{AtomicU64, Ordering}, }; use thiserror::Error; -use url::{ParseError, Url}; +use url::Url; /// An HTTP Client #[derive(Debug)] @@ -69,14 +68,6 @@ impl Provider { } } -impl TryFrom<&str> for super::Provider { - type Error = ParseError; - - fn try_from(src: &str) -> Result { - Ok(super::Provider(Provider::new(Url::parse(src)?))) - } -} - impl Clone for Provider { fn clone(&self) -> Self { Self { diff --git a/crates/ethers-providers/src/lib.rs b/crates/ethers-providers/src/lib.rs index a6ecd38b..474c29b1 100644 --- a/crates/ethers-providers/src/lib.rs +++ b/crates/ethers-providers/src/lib.rs @@ -4,13 +4,15 @@ //! //! TODO: WebSockets, multiple backends, popular APIs etc. -mod provider; mod http; +mod provider; use async_trait::async_trait; use serde::{Deserialize, Serialize}; use std::{error::Error, fmt::Debug}; +pub use provider::Provider; + /// An HTTP provider for interacting with an Ethereum-compatible blockchain pub type HttpProvider = Provider; @@ -26,4 +28,3 @@ pub trait JsonRpcClient: Debug { params: Option, ) -> Result; } - diff --git a/crates/ethers-providers/src/provider.rs b/crates/ethers-providers/src/provider.rs index e88fc877..eba2bfc0 100644 --- a/crates/ethers-providers/src/provider.rs +++ b/crates/ethers-providers/src/provider.rs @@ -4,9 +4,11 @@ use ethers_types::{ }; use ethers_utils as utils; -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use std::{error::Error, fmt::Debug}; +use crate::{http::Provider as HttpProvider, JsonRpcClient}; +use serde::Deserialize; +use url::{ParseError, Url}; + +use std::{convert::TryFrom, fmt::Debug}; /// An abstract provider for interacting with the [Ethereum JSON RPC /// API](https://github.com/ethereum/wiki/wiki/JSON-RPC) @@ -148,3 +150,11 @@ impl Provider

{ self.0.request("eth_getBalance", Some(&[from, block])).await } } + +impl TryFrom<&str> for Provider { + type Error = ParseError; + + fn try_from(src: &str) -> Result { + Ok(Provider(HttpProvider::new(Url::parse(src)?))) + } +} diff --git a/crates/ethers-signers/Cargo.toml b/crates/ethers-signers/Cargo.toml index f63a327b..12d6db03 100644 --- a/crates/ethers-signers/Cargo.toml +++ b/crates/ethers-signers/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Georgios Konstantopoulos "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +ethers-types = { path = "../ethers-types" } +ethers-providers = { path = "../ethers-providers" } +ethers-utils = { path = "../ethers-utils" } diff --git a/crates/ethers-signers/src/client.rs b/crates/ethers-signers/src/client.rs index 86a257a4..2b05e6b6 100644 --- a/crates/ethers-signers/src/client.rs +++ b/crates/ethers-signers/src/client.rs @@ -1,9 +1,7 @@ -use crate::{ - providers::{JsonRpcClient, Provider}, - signers::Signer, - types::{Address, BlockNumber, Overrides, TransactionRequest, TxHash}, - utils, -}; +use crate::Signer; + +use ethers_providers::{JsonRpcClient, Provider}; +use ethers_types::{Address, BlockNumber, TransactionRequest, TxHash}; use std::ops::Deref; @@ -79,40 +77,6 @@ impl<'a, S: Signer, P: JsonRpcClient> Client<'a, S, P> { Ok(()) } - /// client.call_contract( - /// addr, - /// "transfer(address,uint256)" - /// vec![0x1234, 100] - /// None, - /// None, - /// ) - pub async fn call_contract( - &self, - to: impl Into

, - signature: &str, - args: &[ethabi::Token], - overrides: Option, - block: Option, - ) -> Result { - // create the data field from the function signature and the arguments - let data = [&utils::id(signature)[..], ðabi::encode(args)].concat(); - - let overrides = overrides.unwrap_or_default(); - let tx = TransactionRequest { - to: Some(to.into()), - data: Some(data.into()), - - // forward the overriden data - from: overrides.from, // let it figure it out itself - gas: overrides.gas, - gas_price: overrides.gas_price, - nonce: overrides.nonce, - value: overrides.value, - }; - - self.send_transaction(tx, block).await - } - pub fn address(&self) -> Address { self.signer .as_ref() diff --git a/crates/ethers-signers/src/lib.rs b/crates/ethers-signers/src/lib.rs index 31e1bb20..1408beae 100644 --- a/crates/ethers-signers/src/lib.rs +++ b/crates/ethers-signers/src/lib.rs @@ -1,7 +1,39 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } +//! Ethereum compatible signers +//! +//! Currently supported: +//! - [x] Private Key +//! - [ ] Encrypted Json +//! - [ ] Ledger +//! - [ ] Trezor +//! +//! Implement the `Signer` trait to add support for new signers, e.g. with Ledger. +//! +//! TODO: We might need a `SignerAsync` trait for HSM use cases? + +mod networks; +pub use networks::instantiated::*; +use networks::Network; + +mod wallet; +pub use wallet::Wallet; + +mod client; +pub(crate) use client::Client; + +use ethers_types::{Address, Signature, Transaction, TransactionRequest}; +use std::error::Error; + +/// Trait for signing transactions and messages +/// +/// Implement this trait to support different signing modes, e.g. Ledger, hosted etc. +pub trait Signer { + type Error: Error; + /// Signs the hash of the provided message after prefixing it + fn sign_message>(&self, message: S) -> Signature; + + /// Signs the transaction + fn sign_transaction(&self, message: TransactionRequest) -> Result; + + /// Returns the signer's Ethereum Address + fn address(&self) -> Address; } diff --git a/crates/ethers-signers/src/mod.rs b/crates/ethers-signers/src/mod.rs deleted file mode 100644 index a53bd50d..00000000 --- a/crates/ethers-signers/src/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Sign and broadcast transactions -//! -//! Implement the `Signer` trait to add support for new signers, e.g. with Ledger. -//! -//! TODO: We might need a `SignerAsync` trait for HSM use cases? -mod networks; -pub use networks::instantiated::*; -use networks::Network; - -mod wallet; -pub use wallet::Wallet; - -mod client; -pub(crate) use client::Client; - -use crate::types::{Address, Signature, Transaction, TransactionRequest}; -use std::error::Error; - -/// Trait for signing transactions and messages -/// -/// Implement this trait to support different signing modes, e.g. Ledger, hosted etc. -pub trait Signer { - type Error: Error; - /// Signs the hash of the provided message after prefixing it - fn sign_message>(&self, message: S) -> Signature; - - /// Signs the transaction - fn sign_transaction(&self, message: TransactionRequest) -> Result; - - /// Returns the signer's Ethereum Address - fn address(&self) -> Address; -} diff --git a/crates/ethers-signers/src/networks.rs b/crates/ethers-signers/src/networks.rs index 84ba0177..0f8ae6bf 100644 --- a/crates/ethers-signers/src/networks.rs +++ b/crates/ethers-signers/src/networks.rs @@ -2,7 +2,7 @@ //! a transaction that is designed to work with testnet does not accidentally work //! with mainnet because the URL was changed. -use crate::types::U64; +use ethers_types::U64; pub trait Network { const CHAIN_ID: Option; @@ -28,7 +28,7 @@ impl Network for EIP155Disabled { pub mod instantiated { use super::*; - use crate::signers::Wallet; + use crate::Wallet; /// A Wallet instantiated with chain_id = 1 for Ethereum Mainnet. pub type MainnetWallet = Wallet; diff --git a/crates/ethers-signers/src/wallet.rs b/crates/ethers-signers/src/wallet.rs index 542f5575..be03059f 100644 --- a/crates/ethers-signers/src/wallet.rs +++ b/crates/ethers-signers/src/wallet.rs @@ -1,10 +1,12 @@ -use crate::{ - providers::{JsonRpcClient, Provider}, - signers::{Client, Network, Signer}, - types::{Address, PrivateKey, PublicKey, Signature, Transaction, TransactionRequest, TxError}, +use crate::{Client, Network, Signer}; + +use ethers_providers::{JsonRpcClient, Provider}; + +use ethers_types::{ + rand::Rng, secp256k1, Address, PrivateKey, PublicKey, Signature, Transaction, + TransactionRequest, TxError, }; -use rand::Rng; use std::{marker::PhantomData, str::FromStr}; /// A keypair diff --git a/crates/ethers-types/Cargo.toml b/crates/ethers-types/Cargo.toml index 44d7e054..41bf696d 100644 --- a/crates/ethers-types/Cargo.toml +++ b/crates/ethers-types/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" authors = ["Georgios Konstantopoulos "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] ethers-utils = { path = "../ethers-utils" } @@ -19,3 +17,7 @@ thiserror = { version = "1.0.19", default-features = false } secp256k1 = { version = "0.17.2", default-features = false, features = ["std", "recovery", "rand"] } rand = { version = "0.5.1", default-features = false } # this should be the same rand crate version as the one in secp zeroize = { version = "1.1.0", default-features = false } + +[dev-dependencies] +serde_json = { version = "1.0.53", default-features = false } +rand = { version = "0.5.1" } diff --git a/crates/ethers-types/src/keys.rs b/crates/ethers-types/src/keys.rs index 28cbfa9f..6c088699 100644 --- a/crates/ethers-types/src/keys.rs +++ b/crates/ethers-types/src/keys.rs @@ -208,7 +208,7 @@ impl From for Address { #[cfg(test)] mod tests { use super::*; - use crate::types::Bytes; + use crate::Bytes; use rustc_hex::FromHex; #[test] diff --git a/crates/ethers-types/src/lib.rs b/crates/ethers-types/src/lib.rs index 7f45fa0d..10b3189a 100644 --- a/crates/ethers-types/src/lib.rs +++ b/crates/ethers-types/src/lib.rs @@ -23,3 +23,10 @@ pub use block::{Block, BlockId, BlockNumber}; mod log; pub use log::{Filter, Log, ValueOrArray}; + +// re-export the non-standard rand version so that other crates don't use the +// wrong one by accident +pub use rand; + +// re-export libsecp +pub use secp256k1; diff --git a/crates/ethers-types/src/signature.rs b/crates/ethers-types/src/signature.rs index aeddaf9e..71bd8d88 100644 --- a/crates/ethers-types/src/signature.rs +++ b/crates/ethers-types/src/signature.rs @@ -192,7 +192,7 @@ impl From for RecoveryMessage { #[cfg(test)] mod tests { use super::*; - use crate::types::PrivateKey; + use crate::PrivateKey; #[test] fn recover_signature_from_message() { diff --git a/crates/ethers-types/src/transaction.rs b/crates/ethers-types/src/transaction.rs index da780fe7..0e5c862e 100644 --- a/crates/ethers-types/src/transaction.rs +++ b/crates/ethers-types/src/transaction.rs @@ -11,24 +11,24 @@ use std::str::FromStr; pub struct Overrides { /// Sender address or ENS name #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) from: Option
, + pub from: Option
, /// Supplied gas (None for sensible default) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) gas: Option, + pub gas: Option, /// Gas price (None for sensible default) #[serde(rename = "gasPrice")] #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) gas_price: Option, + pub gas_price: Option, /// Transfered value (None for no transfer) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) value: Option, + pub value: Option, /// Transaction nonce (None for next available nonce) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) nonce: Option, + pub nonce: Option, } /// Parameters for sending a transaction @@ -36,33 +36,33 @@ pub struct Overrides { pub struct TransactionRequest { /// Sender address or ENS name #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) from: Option
, + pub from: Option
, /// Recipient address (None for contract creation) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) to: Option
, + pub to: Option
, /// Supplied gas (None for sensible default) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) gas: Option, + pub gas: Option, /// Gas price (None for sensible default) #[serde(rename = "gasPrice")] #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) gas_price: Option, + pub gas_price: Option, /// Transfered value (None for no transfer) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) value: Option, + pub value: Option, /// The compiled code of a contract OR the first 4 bytes of the hash of the /// invoked method signature and encoded parameters. For details see Ethereum Contract ABI #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) data: Option, + pub data: Option, /// Transaction nonce (None for next available nonce) #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) nonce: Option, + pub nonce: Option, } impl TransactionRequest {