ethers-types docs

This commit is contained in:
Georgios Konstantopoulos 2020-05-28 17:53:22 +03:00
parent bc523b6d60
commit e51fbd06b0
No known key found for this signature in database
GPG Key ID: FA607837CD26EDBC
8 changed files with 134 additions and 47 deletions

View File

@ -31,12 +31,7 @@ impl<'a, 'b, P, N, D: Detokenize> Event<'a, 'b, P, N, D> {
} }
pub fn topic0<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self { pub fn topic0<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.filter.topics.push(topic.into()); self.filter.topics[0] = topic.into();
self
}
pub fn topics(mut self, topics: &[ValueOrArray<H256>]) -> Self {
self.filter.topics.extend_from_slice(topics);
self self
} }
} }

View File

@ -1,5 +1,5 @@
//! This module implements extensions to the `ethabi` API. //! This module implements extensions to the `ethabi` API.
//! Taken from: https://github.com/gnosis/ethcontract-rs/blob/master/common/src/abiext.rs // Adapted from [Gnosis' ethcontract](https://github.com/gnosis/ethcontract-rs/blob/master/common/src/abiext.rs)
use crate::Selector; use crate::Selector;
use ethers_utils::id; use ethers_utils::id;

View File

@ -1,5 +1,5 @@
//! Contract Functions Output types. //! Contract Functions Output types.
//! Adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/contract/tokens.rs // Adapted from: [rust-web3](https://github.com/tomusdrw/rust-web3/blob/master/src/contract/tokens.rs)
#![allow(clippy::all)] #![allow(clippy::all)]
use crate::{abi::Token, Address, Bytes, H256, U128, U256}; use crate::{abi::Token, Address, Bytes, H256, U128, U256};

View File

@ -1,6 +1,7 @@
// Adapted from https://github.com/tomusdrw/rust-web3/blob/master/src/types/log.rs
use crate::{Address, BlockNumber, Bytes, H256, U256, U64}; use crate::{Address, BlockNumber, Bytes, H256, U256, U64};
use ethers_utils::keccak256; use ethers_utils::keccak256;
use serde::{Deserialize, Serialize}; use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
use std::str::FromStr; use std::str::FromStr;
/// A log produced by a transaction. /// A log produced by a transaction.
@ -60,7 +61,7 @@ pub struct Log {
pub removed: Option<bool>, pub removed: Option<bool>,
} }
/// Filter /// Filter for
#[derive(Default, Debug, PartialEq, Clone, Serialize)] #[derive(Default, Debug, PartialEq, Clone, Serialize)]
pub struct Filter { pub struct Filter {
/// From Block /// From Block
@ -78,9 +79,10 @@ pub struct Filter {
address: Option<Address>, address: Option<Address>,
/// Topics /// Topics
#[serde(skip_serializing_if = "Vec::is_empty")] // TODO: We could improve the low level API here by using ethabi's RawTopicFilter
// TODO: Split in an event name + 3 topics // and/or TopicFilter
pub topics: Vec<ValueOrArray<H256>>, #[serde(serialize_with = "skip_nones")]
pub topics: [Option<ValueOrArray<H256>>; 4],
/// Limit /// Limit
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -117,16 +119,30 @@ impl Filter {
/// 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()));
self.topic(hash) self.topic0(hash)
} }
pub fn topic<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self { /// Sets topic0 (the event name for non-anonymous events)
self.topics.push(topic.into()); pub fn topic0<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.topics[0] = Some(topic.into());
self self
} }
pub fn topics(mut self, topics: &[ValueOrArray<H256>]) -> Self { /// Sets the 1st indexed topic
self.topics.extend_from_slice(topics); pub fn topic1<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.topics[1] = Some(topic.into());
self
}
/// Sets the 2nd indexed topic
pub fn topic2<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.topics[2] = Some(topic.into());
self
}
/// Sets the 3rd indexed topic
pub fn topic3<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
self.topics[3] = Some(topic.into());
self self
} }
@ -136,12 +152,17 @@ impl Filter {
} }
} }
/// Union type for representing a single value or a vector of values inside a filter
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum ValueOrArray<T> { pub enum ValueOrArray<T> {
/// A single value
Value(T), Value(T),
/// A vector of values
Array(Vec<T>), Array(Vec<T>),
} }
// TODO: Implement more common types - or adjust this to work with all Tokenizable items
impl From<H256> for ValueOrArray<H256> { impl From<H256> for ValueOrArray<H256> {
fn from(src: H256) -> Self { fn from(src: H256) -> Self {
ValueOrArray::Value(src) ValueOrArray::Value(src)
@ -156,13 +177,21 @@ impl From<Address> for ValueOrArray<H256> {
} }
} }
impl From<U256> for ValueOrArray<H256> {
fn from(src: U256) -> Self {
let mut bytes = [0; 32];
src.to_big_endian(&mut bytes);
ValueOrArray::Value(H256::from(bytes))
}
}
impl<T> Serialize for ValueOrArray<T> impl<T> Serialize for ValueOrArray<T>
where where
T: Serialize, T: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: Serializer,
{ {
match self { match self {
ValueOrArray::Value(inner) => inner.serialize(serializer), ValueOrArray::Value(inner) => inner.serialize(serializer),
@ -170,3 +199,45 @@ where
} }
} }
} }
// adapted from https://github.com/serde-rs/serde/issues/550#issuecomment-246746639
fn skip_nones<T, S>(elements: &[Option<T>], serializer: S) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
// get number of Some elements
let len = elements.iter().filter(|opt| opt.is_some()).count();
let mut seq = serializer.serialize_seq(Some(len))?;
for elem in elements {
if elem.is_some() {
seq.serialize_element(elem)?;
}
}
seq.end()
}
#[cfg(test)]
mod tests {
use super::*;
use ethers_utils::serialize;
#[test]
fn filter_serialization_test() {
let t1 = "9729a6fbefefc8f6005933898b13dc45c3a2c8b7"
.parse::<Address>()
.unwrap();
let t3 = U256::from(123);
let filter = Filter::new()
.address_str("f817796F60D268A36a57b8D2dF1B97B14C0D0E1d")
.unwrap()
.event("ValueChanged(address,string,string)") // event name
.topic1(t1)
.topic2(t3);
dbg!(&filter);
let ser = serialize(&filter).to_string();
assert_eq!(ser, "{\"address\":\"0xf817796f60d268a36a57b8d2df1b97b14c0d0e1d\",\"topics\":[\"0xe826f71647b8486f2bae59832124c70792fba044036720a54ec8dacdd5df4fcb\",\"0x0000000000000000000000009729a6fbefefc8f6005933898b13dc45c3a2c8b7\",\"0x000000000000000000000000000000000000000000000000000000000000007b\"]}");
}
}

View File

@ -1,11 +1,14 @@
pub type Selector = [u8; 4]; pub type Selector = [u8; 4];
// Re-export common ethereum datatypes with more specific names // Re-export common ethereum datatypes with more specific names
/// A transaction Hash
pub use ethereum_types::H256 as TxHash; pub use ethereum_types::H256 as TxHash;
pub use ethereum_types::{Address, Bloom, H160, H256, U128, U256, U64}; pub use ethereum_types::{Address, Bloom, H160, H256, U128, U256, U64};
mod transaction; mod transaction;
pub use transaction::{Overrides, Transaction, TransactionReceipt, TransactionRequest}; pub use transaction::{Transaction, TransactionReceipt, TransactionRequest};
mod bytes; mod bytes;
pub use bytes::Bytes; pub use bytes::Bytes;

View File

@ -6,31 +6,6 @@ use rlp::RlpStream;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
/// Override params for interacting with a contract
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct Overrides {
/// Sender address or ENS name
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<Address>,
/// Supplied gas (None for sensible default)
#[serde(skip_serializing_if = "Option::is_none")]
pub gas: Option<U256>,
/// Gas price (None for sensible default)
#[serde(rename = "gasPrice")]
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_price: Option<U256>,
/// Transfered value (None for no transfer)
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<U256>,
/// Transaction nonce (None for next available nonce)
#[serde(skip_serializing_if = "Option::is_none")]
pub nonce: Option<U256>,
}
/// Parameters for sending a transaction /// Parameters for sending a transaction
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Debug)] #[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct TransactionRequest { pub struct TransactionRequest {

View File

@ -24,12 +24,17 @@ impl FromStr for PrivateKey {
} }
} }
/// An error which may be thrown when attempting to sign a transaction with
/// missing fields
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
pub enum TxError { pub enum TxError {
/// Thrown if the `nonce` field is missing
#[error("no nonce was specified")] #[error("no nonce was specified")]
NonceMissing, NonceMissing,
/// Thrown if the `gas_price` field is missing
#[error("no gas price was specified")] #[error("no gas price was specified")]
GasPriceMissing, GasPriceMissing,
/// Thrown if the `gas` field is missing
#[error("no gas was specified")] #[error("no gas was specified")]
GasMissing, GasMissing,
} }

View File

@ -1,5 +1,40 @@
//! Various Ethereum Related Datatypes //! # Ethereum Related DataTypes
//!
//! This library provides type definitions for Ethereum's main datatypes
//!
//! # Signing an ethereum-prefixed message
//!
//! Signing in Ethereum is done by first prefixing the message with
//! `"\x19Ethereum Signed Message:\n" + message.length`, and then
//! signing the hash of the result.
//!
//! ```rust
//! use ethers_types::{PrivateKey, Address};
//!
//! let message = "Some data";
//! let key = PrivateKey::new(&mut rand::thread_rng());
//! let address = Address::from(key);
//!
//! // Sign the message
//! let signature = key.sign(message);
//!
//! // Recover the signer from the message
//! let recovered = signature.recover(message).unwrap();
//!
//! assert_eq!(recovered, address);
//! ```
//!
//! # ABI Encoding and Decoding
//!
//! This crate re-exports the [`ethabi`](http://docs.rs/ethabi) crate's functions
//! under the `abi` module
//!
//! # A note about `secp256k1` and `rand`
//!
//! The version of `rand` used in the `secp256k1` crate is not compatible with the
//! latest one in crates at the time of writing (rand version 0.5.1, secp256k1 version 0.17.1)
//! As a result, the RNGs used for generating private keys must use a compatible rand crate
//! version. For convenience, we re-export it so that consumers can use it as `ethers_types::rand`.
mod crypto; mod crypto;
pub use crypto::*; pub use crypto::*;
@ -8,3 +43,6 @@ pub use chainstate::*;
#[cfg(feature = "abi")] #[cfg(feature = "abi")]
pub mod abi; pub mod abi;
// Convenience re-export
pub use ethers_utils as utils;