Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

feat(signers): make Signer on Client optional #34

Merged
merged 1 commit into from
Jun 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ethers-contract/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ where

// create the tx object. Since we're deploying a contract, `to` is `None`
let tx = TransactionRequest {
from: Some(self.client.address()),
to: None,
data: Some(data),
..Default::default()
Expand Down
37 changes: 36 additions & 1 deletion ethers-contract/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ pub use common::*;
#[cfg(not(feature = "celo"))]
mod eth_tests {
use super::*;
use ethers::{providers::StreamExt, types::Address, utils::Ganache};
use ethers::{
providers::{Http, Provider, StreamExt},
signers::Client,
types::Address,
utils::Ganache,
};
use serial_test::serial;
use std::convert::TryFrom;

#[tokio::test]
#[serial]
Expand Down Expand Up @@ -133,6 +139,35 @@ mod eth_tests {
assert_eq!(log.new_value, i.to_string());
}
}

#[tokio::test]
#[serial]
async fn signer_on_node() {
let (abi, bytecode) = compile();
let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
let deployer = "3cDB3d9e1B74692Bb1E3bb5fc81938151cA64b02"
.parse::<Address>()
.unwrap();
let client = Client::from(provider).with_sender(deployer);
let (_ganache, contract) = deploy(&client, abi, bytecode).await;

// make a call without the signer
let _tx = contract
.method::<_, H256>("setValue", "hi".to_owned())
.unwrap()
.send()
.await
.unwrap()
.await
.unwrap();
let value: String = contract
.method::<_, String>("getValue", ())
.unwrap()
.call()
.await
.unwrap();
assert_eq!(value, "hi");
}
}

#[cfg(feature = "celo")]
Expand Down
49 changes: 37 additions & 12 deletions ethers-signers/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ use thiserror::Error;
/// [`Provider`]: ethers_providers::Provider
pub struct Client<P, S> {
pub(crate) provider: Provider<P>,
pub(crate) signer: S,
pub(crate) signer: Option<S>,
pub(crate) address: Address,
}

Expand Down Expand Up @@ -102,15 +102,19 @@ where
let address = signer.address();
Client {
provider,
signer,
signer: Some(signer),
address,
}
}

/// Signs a message with the internal signer, or if none is present it will make a call to
/// the connected node's `eth_call` API.
pub async fn sign_message<T: Into<Bytes>>(&self, msg: T) -> Result<Signature, ClientError> {
Ok(self.signer.sign_message(msg.into()))
Ok(if let Some(ref signer) = self.signer {
signer.sign_message(msg.into())
} else {
self.provider.sign(msg, &self.address()).await?
})
}

/// Signs and broadcasts the transaction. The optional parameter `block` can be passed so that
Expand All @@ -131,11 +135,13 @@ where
// fill any missing fields
self.fill_transaction(&mut tx, block).await?;

// sign the transaction with the network
let signed_tx = self.signer.sign_transaction(tx).map_err(Into::into)?;

// broadcast it
Ok(self.provider.send_raw_transaction(&signed_tx).await?)
// sign the transaction and broadcast it
Ok(if let Some(ref signer) = self.signer {
let signed_tx = signer.sign_transaction(tx).map_err(Into::into)?;
self.provider.send_raw_transaction(&signed_tx).await?
} else {
self.provider.send_transaction(tx).await?
})
}

async fn fill_transaction(
Expand Down Expand Up @@ -166,7 +172,7 @@ where

/// Returns the client's address
pub fn address(&self) -> Address {
self.signer.address()
self.address
}

/// Returns a reference to the client's provider
Expand All @@ -175,8 +181,8 @@ where
}

/// Returns a reference to the client's signer
pub fn signer(&self) -> &S {
&self.signer
pub fn signer(&self) -> Option<&S> {
self.signer.as_ref()
}

/// Sets the signer and returns a mutable reference to self so that it can be used in chained
Expand All @@ -188,7 +194,8 @@ where
P: Clone,
{
let mut this = self.clone();
this.signer = signer;
this.address = signer.address();
this.signer = Some(signer);
this
}

Expand All @@ -204,6 +211,14 @@ where
this.provider = provider;
this
}

/// Sets the address which will be used for interacting with the blockchain.
/// Useful if no signer is set and you want to specify a default sender for
/// your transactions
pub fn with_sender<T: Into<Address>>(mut self, address: T) -> Self {
self.address = address.into();
self
}
}

/// Calls the future if `item` is None, otherwise returns a `futures::ok`
Expand All @@ -228,3 +243,13 @@ impl<P, S> Deref for Client<P, S> {
&self.provider
}
}

impl<P: JsonRpcClient, S> From<Provider<P>> for Client<P, S> {
fn from(provider: Provider<P>) -> Self {
Self {
provider,
signer: None,
address: Address::zero(),
}
}
}
2 changes: 1 addition & 1 deletion ethers-signers/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl Wallet {
let address = self.address();
Client {
address,
signer: self,
signer: Some(self),
provider,
}
}
Expand Down