lints and more examples

This commit is contained in:
Georgios Konstantopoulos 2020-05-24 19:14:27 +03:00
parent 4b6fbf00a8
commit 8a8e33c9c8
No known key found for this signature in database
GPG Key ID: FA607837CD26EDBC
9 changed files with 62 additions and 19 deletions

View File

@ -4,16 +4,21 @@ use std::str::FromStr;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), failure::Error> { async fn main() -> Result<(), failure::Error> {
// connect to the network
let provider = HttpProvider::try_from("http://localhost:8545")?; let provider = HttpProvider::try_from("http://localhost:8545")?;
// create a wallet and connect it to the provider
let client = MainnetWallet::from_str( let client = MainnetWallet::from_str(
"d8ebe1e50cfea1f9961908d9df28e64bb163fee9ee48320361b2eb0a54974269", "d8ebe1e50cfea1f9961908d9df28e64bb163fee9ee48320361b2eb0a54974269",
)? )?
.connect(&provider); .connect(&provider);
// get the account's nonce
let nonce = provider let nonce = provider
.get_transaction_count(client.signer.address, None) .get_transaction_count(client.signer.address, None)
.await?; .await?;
// craft the transaction
let tx = UnsignedTransaction { let tx = UnsignedTransaction {
to: Some("986eE0C8B91A58e490Ee59718Cca41056Cf55f24".parse().unwrap()), to: Some("986eE0C8B91A58e490Ee59718Cca41056Cf55f24".parse().unwrap()),
gas: 21000.into(), gas: 21000.into(),
@ -23,8 +28,10 @@ async fn main() -> Result<(), failure::Error> {
nonce, nonce,
}; };
// send it!
let tx = client.send_transaction(tx).await?; let tx = client.send_transaction(tx).await?;
// get the mined tx
let tx = client.get_transaction(tx.hash).await?; let tx = client.get_transaction(tx.hash).await?;
println!("{}", serde_json::to_string(&tx)?); println!("{}", serde_json::to_string(&tx)?);

17
examples/sign.rs Normal file
View File

@ -0,0 +1,17 @@
use ethers::{MainnetWallet as Wallet, Signer};
fn main() {
let message = "Some data";
let wallet = Wallet::new(&mut rand::thread_rng());
// sign a message
let signature = wallet.sign_message(message);
println!("Produced signature {}", signature);
// recover the address that signed it
let recovered = signature.recover(message).unwrap();
assert_eq!(recovered, wallet.address);
println!("Verified signature produced by {:?}!", wallet.address);
}

View File

@ -6,11 +6,12 @@ use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), failure::Error> { async fn main() -> Result<(), failure::Error> {
// connect to the network
let provider = HttpProvider::try_from("http://localhost:8545")?; let provider = HttpProvider::try_from("http://localhost:8545")?;
let from = "4916064D2E9C1b2ccC466EEc3d30B2b08F1C130D".parse()?; let from = "4916064D2E9C1b2ccC466EEc3d30B2b08F1C130D".parse()?;
let tx_hash = provider // craft the tx
.send_transaction(TransactionRequest { let tx = TransactionRequest {
from, from,
to: Some("9A7e5d4bcA656182e66e33340d776D1542143006".parse()?), to: Some("9A7e5d4bcA656182e66e33340d776D1542143006".parse()?),
value: Some(1000u64.into()), value: Some(1000u64.into()),
@ -18,8 +19,10 @@ async fn main() -> Result<(), failure::Error> {
gas_price: None, gas_price: None,
data: None, data: None,
nonce: None, nonce: None,
}) };
.await?;
// broadcast it via the eth_sendTransaction API
let tx_hash = provider.send_transaction(tx).await?;
let tx = provider.get_transaction(tx_hash).await?; let tx = provider.get_transaction(tx_hash).await?;

View File

@ -19,7 +19,7 @@ pub mod providers;
pub use providers::HttpProvider; pub use providers::HttpProvider;
pub mod signers; pub mod signers;
pub use signers::{AnyWallet, MainnetWallet}; pub use signers::{AnyWallet, MainnetWallet, Signer};
/// Ethereum related datatypes /// Ethereum related datatypes
pub mod types; pub mod types;

View File

@ -6,6 +6,7 @@
mod http; mod http;
use crate::{ use crate::{
signers::{Client, Signer},
types::{Address, BlockNumber, Bytes, Transaction, TransactionRequest, TxHash, U256}, types::{Address, BlockNumber, Bytes, Transaction, TransactionRequest, TxHash, U256},
utils, utils,
}; };
@ -37,6 +38,14 @@ 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,
provider: self,
}
}
pub async fn get_block_number(&self) -> Result<U256, P::Error> { pub async fn get_block_number(&self) -> Result<U256, P::Error> {
self.0.request("eth_blockNumber", None::<()>).await self.0.request("eth_blockNumber", None::<()>).await
} }

View File

@ -6,7 +6,7 @@ use crate::{
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Client<'a, S, P> { pub struct Client<'a, S, P> {
pub(super) provider: &'a Provider<P>, pub provider: &'a Provider<P>,
pub signer: S, pub signer: S,
} }

View File

@ -1,3 +1,4 @@
//! Sign and broadcast transactions
mod networks; mod networks;
pub use networks::instantiated::*; pub use networks::instantiated::*;
use networks::Network; use networks::Network;
@ -6,7 +7,7 @@ mod wallet;
pub use wallet::Wallet; pub use wallet::Wallet;
mod client; mod client;
use client::Client; pub(crate) use client::Client;
use crate::types::{Signature, Transaction, UnsignedTransaction}; use crate::types::{Signature, Transaction, UnsignedTransaction};

View File

@ -4,12 +4,13 @@ use crate::{
utils::hash_message, utils::hash_message,
}; };
use rustc_hex::ToHex;
use secp256k1::{ use secp256k1::{
recovery::{RecoverableSignature, RecoveryId}, recovery::{RecoverableSignature, RecoveryId},
Error as Secp256k1Error, Message, Secp256k1, Error as Secp256k1Error, Message, Secp256k1,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::convert::TryFrom; use std::{convert::TryFrom, fmt};
use thiserror::Error; use thiserror::Error;
/// An error involving a signature. /// An error involving a signature.
@ -47,6 +48,13 @@ pub struct Signature {
pub v: u8, pub v: u8,
} }
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sig = <[u8; 65]>::from(self);
write!(f, "{}", sig.to_hex::<String>())
}
}
impl Signature { impl Signature {
/// Recovers the Ethereum address which was used to sign the given message. /// Recovers the Ethereum address which was used to sign the given message.
/// ///
@ -106,9 +114,7 @@ impl<'a> TryFrom<&'a [u8]> for Signature {
/// Parses a raw signature which is expected to be 65 bytes long where /// Parses a raw signature which is expected to be 65 bytes long where
/// the first 32 bytes is the `r` value, the second 32 bytes the `s` value /// the first 32 bytes is the `r` value, the second 32 bytes the `s` value
/// and the final byte is the `v` value in 'Electrum' notation. /// and the final byte is the `v` value in 'Electrum' notation.
fn try_from(raw_signature: &'a [u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let bytes = raw_signature.as_ref();
if bytes.len() != 65 { if bytes.len() != 65 {
return Err(SignatureError::InvalidLength(bytes.len())); return Err(SignatureError::InvalidLength(bytes.len()));
} }

View File

@ -87,7 +87,7 @@ impl UnsignedTransaction {
rlp.begin_list(9); rlp.begin_list(9);
self.rlp_base(&mut rlp); self.rlp_base(&mut rlp);
rlp.append(&chain_id.unwrap_or(U64::zero())); rlp.append(&chain_id.unwrap_or_else(U64::zero));
rlp.append(&0u8); rlp.append(&0u8);
rlp.append(&0u8); rlp.append(&0u8);