wip
This commit is contained in:
parent
3f313ede01
commit
e7c9e19409
File diff suppressed because it is too large
Load Diff
|
@ -5,10 +5,10 @@ members = [
|
||||||
# "./crates/ethers-abi",
|
# "./crates/ethers-abi",
|
||||||
# "./crates/ethers-contract",
|
# "./crates/ethers-contract",
|
||||||
# "./crates/ethers-derive",
|
# "./crates/ethers-derive",
|
||||||
# "./crates/ethers-providers",
|
"./crates/ethers-providers",
|
||||||
# "./crates/ethers-signers",
|
# "./crates/ethers-signers",
|
||||||
"./crates/ethers-types",
|
"./crates/ethers-types",
|
||||||
# "./crates/ethers-utils",
|
"./crates/ethers-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
# [dependencies]
|
# [dependencies]
|
||||||
|
|
|
@ -4,6 +4,13 @@ version = "0.1.0"
|
||||||
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ethers-types = { path = "../ethers-types" }
|
||||||
|
ethers-utils = { path = "../ethers-utils" }
|
||||||
|
|
||||||
|
async-trait = { version = "0.1.31", default-features = false }
|
||||||
|
reqwest = { version = "0.10.4", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
|
serde = { version = "1.0.110", default-features = false, features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.53", default-features = false }
|
||||||
|
thiserror = { version = "1.0.19", default-features = false }
|
||||||
|
url = { version = "2.1.1", default-features = false }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Minimal HTTP JSON-RPC 2.0 Client
|
//! Minimal HTTP JSON-RPC 2.0 Client
|
||||||
//! The request/response code is taken from [here](https://github.com/althea-net/guac_rs/blob/master/web3/src/jsonrpc)
|
//! The request/response code is taken from [here](https://github.com/althea-net/guac_rs/blob/master/web3/src/jsonrpc)
|
||||||
use crate::providers::JsonRpcClient;
|
use crate::JsonRpcClient;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use reqwest::{Client, Error as ReqwestError};
|
use reqwest::{Client, Error as ReqwestError};
|
|
@ -1,7 +1,29 @@
|
||||||
#[cfg(test)]
|
//! Ethereum compatible providers
|
||||||
mod tests {
|
//! Currently supported:
|
||||||
#[test]
|
//! - Raw HTTP POST requests
|
||||||
fn it_works() {
|
//!
|
||||||
assert_eq!(2 + 2, 4);
|
//! TODO: WebSockets, multiple backends, popular APIs etc.
|
||||||
}
|
|
||||||
|
mod provider;
|
||||||
|
mod http;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{error::Error, fmt::Debug};
|
||||||
|
|
||||||
|
/// An HTTP provider for interacting with an Ethereum-compatible blockchain
|
||||||
|
pub type HttpProvider = Provider<http::Provider>;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
/// Implement this trait in order to plug in different backends
|
||||||
|
pub trait JsonRpcClient: Debug {
|
||||||
|
type Error: Error;
|
||||||
|
|
||||||
|
/// Sends a request with the provided method and the params serialized as JSON
|
||||||
|
async fn request<T: Serialize + Send + Sync, R: for<'a> Deserialize<'a>>(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
params: Option<T>,
|
||||||
|
) -> Result<R, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,13 @@
|
||||||
//! Ethereum compatible providers
|
use ethers_types::{
|
||||||
//! Currently supported:
|
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
|
||||||
//! - Raw HTTP POST requests
|
TransactionRequest, TxHash, U256,
|
||||||
//!
|
|
||||||
//! TODO: WebSockets, multiple backends, popular APIs etc.
|
|
||||||
mod http;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
signers::{Client, Signer},
|
|
||||||
types::{
|
|
||||||
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
|
|
||||||
TransactionRequest, TxHash, U256,
|
|
||||||
},
|
|
||||||
utils,
|
|
||||||
};
|
};
|
||||||
|
use ethers_utils as utils;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{error::Error, fmt::Debug};
|
use std::{error::Error, fmt::Debug};
|
||||||
|
|
||||||
/// An HTTP provider for interacting with an Ethereum-compatible blockchain
|
|
||||||
pub type HttpProvider = Provider<http::Provider>;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
/// Implement this trait in order to plug in different backends
|
|
||||||
pub trait JsonRpcClient: Debug {
|
|
||||||
type Error: Error;
|
|
||||||
|
|
||||||
/// Sends a request with the provided method and the params serialized as JSON
|
|
||||||
async fn request<T: Serialize + Send + Sync, R: for<'a> Deserialize<'a>>(
|
|
||||||
&self,
|
|
||||||
method: &str,
|
|
||||||
params: Option<T>,
|
|
||||||
) -> Result<R, Self::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An abstract provider for interacting with the [Ethereum JSON RPC
|
/// An abstract provider for interacting with the [Ethereum JSON RPC
|
||||||
/// API](https://github.com/ethereum/wiki/wiki/JSON-RPC)
|
/// API](https://github.com/ethereum/wiki/wiki/JSON-RPC)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -41,16 +15,6 @@ pub struct Provider<P>(P);
|
||||||
|
|
||||||
// JSON RPC bindings
|
// JSON RPC bindings
|
||||||
impl<P: JsonRpcClient> Provider<P> {
|
impl<P: JsonRpcClient> Provider<P> {
|
||||||
/// Connects to a signer and returns a client
|
|
||||||
pub fn connect<S: Signer>(&self, signer: S) -> Client<S, P> {
|
|
||||||
Client {
|
|
||||||
signer: Some(signer),
|
|
||||||
provider: self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cost related
|
|
||||||
|
|
||||||
/// Gets the current gas price as estimated by the node
|
/// Gets the current gas price as estimated by the node
|
||||||
pub async fn get_gas_price(&self) -> Result<U256, P::Error> {
|
pub async fn get_gas_price(&self) -> Result<U256, P::Error> {
|
||||||
self.0.request("eth_gasPrice", None::<()>).await
|
self.0.request("eth_gasPrice", None::<()>).await
|
|
@ -7,6 +7,8 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ethers-utils = { path = "../ethers-utils" }
|
||||||
|
|
||||||
ethereum-types = { version = "0.9.2", default-features = false, features = ["serialize"] }
|
ethereum-types = { version = "0.9.2", default-features = false, features = ["serialize"] }
|
||||||
serde = { version = "1.0.110", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.110", default-features = false, features = ["derive"] }
|
||||||
rlp = { version = "0.4.5", default-features = false }
|
rlp = { version = "0.4.5", default-features = false }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::types::{Address, Bloom, Bytes, H256, U256, U64};
|
use crate::{Address, Bloom, Bytes, H256, U256, U64};
|
||||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||||
|
|
||||||
/// The block type returned from RPC calls.
|
/// The block type returned from RPC calls.
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use crate::{Address, Signature, Transaction, TransactionRequest, H256, U256, U64};
|
||||||
|
use ethers_utils::{hash_message, keccak256};
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use secp256k1::{
|
use secp256k1::{
|
||||||
key::ONE_KEY, Error as SecpError, Message, PublicKey as PubKey, Secp256k1, SecretKey,
|
key::ONE_KEY, Error as SecpError, Message, PublicKey as PubKey, Secp256k1, SecretKey,
|
||||||
|
@ -7,11 +10,6 @@ use std::str::FromStr;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use zeroize::DefaultIsZeroes;
|
use zeroize::DefaultIsZeroes;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
types::{Address, Signature, Transaction, TransactionRequest, H256, U256, U64},
|
|
||||||
utils::{hash_message, keccak256},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A private key on Secp256k1
|
/// A private key on Secp256k1
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct PrivateKey(pub(super) SecretKey);
|
pub struct PrivateKey(pub(super) SecretKey);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::{
|
use crate::{Address, BlockNumber, Bytes, H256, U256, U64};
|
||||||
types::{Address, BlockNumber, Bytes, H256, U256, U64},
|
use ethers_utils::keccak256;
|
||||||
utils::keccak256,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs
|
// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs
|
||||||
use crate::{
|
use crate::{Address, PublicKey, H256};
|
||||||
types::{Address, PublicKey, H256},
|
use ethers_utils::hash_message;
|
||||||
utils::hash_message,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rustc_hex::ToHex;
|
use rustc_hex::ToHex;
|
||||||
use secp256k1::{
|
use secp256k1::{
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
//! Transaction types
|
//! Transaction types
|
||||||
use crate::{
|
use crate::{Address, Bloom, Bytes, Log, Signature, H256, U256, U64};
|
||||||
types::{Address, Bloom, Bytes, Log, Signature, H256, U256, U64},
|
use ethers_utils::keccak256;
|
||||||
utils::keccak256,
|
|
||||||
};
|
|
||||||
use rlp::RlpStream;
|
use rlp::RlpStream;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
|
@ -4,6 +4,8 @@ version = "0.1.0"
|
||||||
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ethereum-types = { version = "0.9.2", default-features = false, features = ["serialize"] }
|
||||||
|
tiny-keccak = { version = "2.0.2", default-features = false }
|
||||||
|
serde = { version = "1.0.110", default-features = false }
|
||||||
|
serde_json = { version = "1.0.53", default-features = false, features = ["alloc"] }
|
||||||
|
|
|
@ -1,7 +1,81 @@
|
||||||
|
//! Various utilities for manipulating Ethereum related dat
|
||||||
|
use ethereum_types::H256;
|
||||||
|
use tiny_keccak::{Hasher, Keccak};
|
||||||
|
|
||||||
|
const PREFIX: &str = "\x19Ethereum Signed Message:\n";
|
||||||
|
|
||||||
|
/// Hash a message according to EIP-191.
|
||||||
|
///
|
||||||
|
/// The data is a UTF-8 encoded string and will enveloped as follows:
|
||||||
|
/// `"\x19Ethereum Signed Message:\n" + message.length + message` and hashed
|
||||||
|
/// using keccak256.
|
||||||
|
pub fn hash_message<S>(message: S) -> H256
|
||||||
|
where
|
||||||
|
S: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
let message = message.as_ref();
|
||||||
|
|
||||||
|
let mut eth_message = format!("{}{}", PREFIX, message.len()).into_bytes();
|
||||||
|
eth_message.extend_from_slice(message);
|
||||||
|
|
||||||
|
keccak256(ð_message).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the Keccak-256 hash of input bytes.
|
||||||
|
// TODO: Add Solidity Keccak256 packing support
|
||||||
|
pub fn keccak256(bytes: &[u8]) -> [u8; 32] {
|
||||||
|
let mut output = [0u8; 32];
|
||||||
|
let mut hasher = Keccak::v256();
|
||||||
|
hasher.update(bytes);
|
||||||
|
hasher.finalize(&mut output);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the function selector as per the contract ABI specification. This
|
||||||
|
/// is defined as the first 4 bytes of the Keccak256 hash of the function
|
||||||
|
/// signature.
|
||||||
|
pub fn id<S: AsRef<str>>(signature: S) -> [u8; 4] {
|
||||||
|
let mut output = [0u8; 4];
|
||||||
|
|
||||||
|
let mut hasher = Keccak::v256();
|
||||||
|
hasher.update(signature.as_ref().as_bytes());
|
||||||
|
hasher.finalize(&mut output);
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize a type. Panics if the type is returns error during serialization.
|
||||||
|
pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
|
||||||
|
serde_json::to_value(t).expect("Types never fail to serialize.")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// test vector taken from:
|
||||||
|
// https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#hashmessage
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn test_hash_message() {
|
||||||
assert_eq!(2 + 2, 4);
|
let hash = hash_message("Hello World");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
hash,
|
||||||
|
"a1de988600a42c4b4ab089b619297c17d53cffae5d5120d82d8a92d0bb3b78f2"
|
||||||
|
.parse()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_function_signature() {
|
||||||
|
// test vector retrieved from
|
||||||
|
// https://web3js.readthedocs.io/en/v1.2.4/web3-eth-abi.html#encodefunctionsignature
|
||||||
|
assert_eq!(id("myMethod(uint256,string)"), [0x24, 0xee, 0x00, 0x97],);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn revert_function_signature() {
|
||||||
|
assert_eq!(id("Error(string)"), [0x08, 0xc3, 0x79, 0xa0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
//! Various utilities for manipulating Ethereum related dat
|
|
||||||
use crate::types::{Selector, H256};
|
|
||||||
use tiny_keccak::{Hasher, Keccak};
|
|
||||||
|
|
||||||
const PREFIX: &str = "\x19Ethereum Signed Message:\n";
|
|
||||||
|
|
||||||
/// Hash a message according to EIP-191.
|
|
||||||
///
|
|
||||||
/// The data is a UTF-8 encoded string and will enveloped as follows:
|
|
||||||
/// `"\x19Ethereum Signed Message:\n" + message.length + message` and hashed
|
|
||||||
/// using keccak256.
|
|
||||||
pub fn hash_message<S>(message: S) -> H256
|
|
||||||
where
|
|
||||||
S: AsRef<[u8]>,
|
|
||||||
{
|
|
||||||
let message = message.as_ref();
|
|
||||||
|
|
||||||
let mut eth_message = format!("{}{}", PREFIX, message.len()).into_bytes();
|
|
||||||
eth_message.extend_from_slice(message);
|
|
||||||
|
|
||||||
keccak256(ð_message).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute the Keccak-256 hash of input bytes.
|
|
||||||
// TODO: Add Solidity Keccak256 packing support
|
|
||||||
pub fn keccak256(bytes: &[u8]) -> [u8; 32] {
|
|
||||||
let mut output = [0u8; 32];
|
|
||||||
let mut hasher = Keccak::v256();
|
|
||||||
hasher.update(bytes);
|
|
||||||
hasher.finalize(&mut output);
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the function selector as per the contract ABI specification. This
|
|
||||||
/// is defined as the first 4 bytes of the Keccak256 hash of the function
|
|
||||||
/// signature.
|
|
||||||
pub fn id<S: AsRef<str>>(signature: S) -> Selector {
|
|
||||||
let mut output = [0u8; 4];
|
|
||||||
|
|
||||||
let mut hasher = Keccak::v256();
|
|
||||||
hasher.update(signature.as_ref().as_bytes());
|
|
||||||
hasher.finalize(&mut output);
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize a type. Panics if the type is returns error during serialization.
|
|
||||||
pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
|
|
||||||
serde_json::to_value(t).expect("Types never fail to serialize.")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// test vector taken from:
|
|
||||||
// https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#hashmessage
|
|
||||||
#[test]
|
|
||||||
fn test_hash_message() {
|
|
||||||
let hash = hash_message("Hello World");
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
hash,
|
|
||||||
"a1de988600a42c4b4ab089b619297c17d53cffae5d5120d82d8a92d0bb3b78f2"
|
|
||||||
.parse()
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn simple_function_signature() {
|
|
||||||
// test vector retrieved from
|
|
||||||
// https://web3js.readthedocs.io/en/v1.2.4/web3-eth-abi.html#encodefunctionsignature
|
|
||||||
assert_eq!(id("myMethod(uint256,string)"), [0x24, 0xee, 0x00, 0x97],);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn revert_function_signature() {
|
|
||||||
assert_eq!(id("Error(string)"), [0x08, 0xc3, 0x79, 0xa0]);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue