diff --git a/ethers-contract/src/factory.rs b/ethers-contract/src/factory.rs index 9d4a8f63..8b5ec5a7 100644 --- a/ethers-contract/src/factory.rs +++ b/ethers-contract/src/factory.rs @@ -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() diff --git a/ethers-contract/tests/contract.rs b/ethers-contract/tests/contract.rs index 87174053..e0907d32 100644 --- a/ethers-contract/tests/contract.rs +++ b/ethers-contract/tests/contract.rs @@ -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] @@ -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::::try_from("http://localhost:8545").unwrap(); + let deployer = "3cDB3d9e1B74692Bb1E3bb5fc81938151cA64b02" + .parse::
() + .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")] diff --git a/ethers-signers/src/client.rs b/ethers-signers/src/client.rs index a907d07b..b6278347 100644 --- a/ethers-signers/src/client.rs +++ b/ethers-signers/src/client.rs @@ -71,7 +71,7 @@ use thiserror::Error; /// [`Provider`]: ethers_providers::Provider pub struct Client { pub(crate) provider: Provider

, - pub(crate) signer: S, + pub(crate) signer: Option, pub(crate) address: Address, } @@ -102,7 +102,7 @@ where let address = signer.address(); Client { provider, - signer, + signer: Some(signer), address, } } @@ -110,7 +110,11 @@ where /// 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>(&self, msg: T) -> Result { - 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 @@ -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( @@ -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 @@ -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 @@ -188,7 +194,8 @@ where P: Clone, { let mut this = self.clone(); - this.signer = signer; + this.address = signer.address(); + this.signer = Some(signer); this } @@ -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>(mut self, address: T) -> Self { + self.address = address.into(); + self + } } /// Calls the future if `item` is None, otherwise returns a `futures::ok` @@ -228,3 +243,13 @@ impl Deref for Client { &self.provider } } + +impl From> for Client { + fn from(provider: Provider

) -> Self { + Self { + provider, + signer: None, + address: Address::zero(), + } + } +} diff --git a/ethers-signers/src/wallet.rs b/ethers-signers/src/wallet.rs index d87b05be..794f19d6 100644 --- a/ethers-signers/src/wallet.rs +++ b/ethers-signers/src/wallet.rs @@ -119,7 +119,7 @@ impl Wallet { let address = self.address(); Client { address, - signer: self, + signer: Some(self), provider, } }