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-contract",
|
||||
# "./crates/ethers-derive",
|
||||
# "./crates/ethers-providers",
|
||||
"./crates/ethers-providers",
|
||||
# "./crates/ethers-signers",
|
||||
"./crates/ethers-types",
|
||||
# "./crates/ethers-utils",
|
||||
"./crates/ethers-utils",
|
||||
]
|
||||
|
||||
# [dependencies]
|
||||
|
|
|
@ -4,6 +4,13 @@ version = "0.1.0"
|
|||
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
||||
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-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
|
||||
//! 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 reqwest::{Client, Error as ReqwestError};
|
|
@ -1,7 +1,29 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
//! Ethereum compatible providers
|
||||
//! Currently supported:
|
||||
//! - Raw HTTP POST requests
|
||||
//!
|
||||
//! 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
|
||||
//! Currently supported:
|
||||
//! - Raw HTTP POST requests
|
||||
//!
|
||||
//! 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_types::{
|
||||
Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt,
|
||||
TransactionRequest, TxHash, U256,
|
||||
};
|
||||
use ethers_utils as utils;
|
||||
|
||||
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>;
|
||||
}
|
||||
|
||||
/// An abstract provider for interacting with the [Ethereum JSON RPC
|
||||
/// API](https://github.com/ethereum/wiki/wiki/JSON-RPC)
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -41,16 +15,6 @@ pub struct Provider<P>(P);
|
|||
|
||||
// JSON RPC bindings
|
||||
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
|
||||
pub async fn get_gas_price(&self) -> Result<U256, P::Error> {
|
||||
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
|
||||
|
||||
[dependencies]
|
||||
ethers-utils = { path = "../ethers-utils" }
|
||||
|
||||
ethereum-types = { version = "0.9.2", default-features = false, features = ["serialize"] }
|
||||
serde = { version = "1.0.110", default-features = false, features = ["derive"] }
|
||||
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};
|
||||
|
||||
/// 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 secp256k1::{
|
||||
key::ONE_KEY, Error as SecpError, Message, PublicKey as PubKey, Secp256k1, SecretKey,
|
||||
|
@ -7,11 +10,6 @@ use std::str::FromStr;
|
|||
use thiserror::Error;
|
||||
use zeroize::DefaultIsZeroes;
|
||||
|
||||
use crate::{
|
||||
types::{Address, Signature, Transaction, TransactionRequest, H256, U256, U64},
|
||||
utils::{hash_message, keccak256},
|
||||
};
|
||||
|
||||
/// A private key on Secp256k1
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PrivateKey(pub(super) SecretKey);
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use crate::{
|
||||
types::{Address, BlockNumber, Bytes, H256, U256, U64},
|
||||
utils::keccak256,
|
||||
};
|
||||
use crate::{Address, BlockNumber, Bytes, H256, U256, U64};
|
||||
use ethers_utils::keccak256;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs
|
||||
use crate::{
|
||||
types::{Address, PublicKey, H256},
|
||||
utils::hash_message,
|
||||
};
|
||||
use crate::{Address, PublicKey, H256};
|
||||
use ethers_utils::hash_message;
|
||||
|
||||
use rustc_hex::ToHex;
|
||||
use secp256k1::{
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//! Transaction types
|
||||
use crate::{
|
||||
types::{Address, Bloom, Bytes, Log, Signature, H256, U256, U64},
|
||||
utils::keccak256,
|
||||
};
|
||||
use crate::{Address, Bloom, Bytes, Log, Signature, H256, U256, U64};
|
||||
use ethers_utils::keccak256;
|
||||
|
||||
use rlp::RlpStream;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
|
|
|
@ -4,6 +4,8 @@ version = "0.1.0"
|
|||
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// test vector taken from:
|
||||
// https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#hashmessage
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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