abuse Deref for using provider methods in the Client

This commit is contained in:
Georgios Konstantopoulos 2020-05-24 19:29:04 +03:00
parent 8a8e33c9c8
commit 0f12894765
No known key found for this signature in database
GPG Key ID: FA607837CD26EDBC
5 changed files with 43 additions and 20 deletions

View File

@ -13,10 +13,8 @@ async fn main() -> Result<(), failure::Error> {
)?
.connect(&provider);
// get the account's nonce
let nonce = provider
.get_transaction_count(client.signer.address, None)
.await?;
// get the account's nonce (we abuse the Deref to access the provider's functions)
let nonce = client.get_transaction_count(client.address(), None).await?;
// craft the transaction
let tx = UnsignedTransaction {
@ -29,7 +27,7 @@ async fn main() -> Result<(), failure::Error> {
};
// send it!
let tx = client.send_transaction(tx).await?;
let tx = client.sign_and_send_transaction(tx).await?;
// get the mined tx
let tx = client.get_transaction(tx.hash).await?;

View File

@ -7,7 +7,7 @@ mod http;
use crate::{
signers::{Client, Signer},
types::{Address, BlockNumber, Bytes, Transaction, TransactionRequest, TxHash, U256},
types::{Address, BlockNumber, Transaction, TransactionRequest, TxHash, U256},
utils,
};
@ -46,10 +46,12 @@ impl<P: JsonRpcClient> Provider<P> {
}
}
/// Gets the latest block number via the `eth_BlockNumber` API
pub async fn get_block_number(&self) -> Result<U256, P::Error> {
self.0.request("eth_blockNumber", None::<()>).await
}
/// Gets the transaction which matches the provided hash via the `eth_getTransactionByHash` API
pub async fn get_transaction<T: Send + Sync + Into<TxHash>>(
&self,
hash: T,
@ -58,12 +60,14 @@ impl<P: JsonRpcClient> Provider<P> {
self.0.request("eth_getTransactionByHash", Some(hash)).await
}
/// Broadcasts the transaction request via the `eth_sendTransaction` API
pub async fn send_transaction(&self, tx: TransactionRequest) -> Result<TxHash, P::Error> {
self.0.request("eth_sendTransaction", Some(tx)).await
}
pub async fn send_raw_transaction(&self, rlp: &Bytes) -> Result<TxHash, P::Error> {
let rlp = utils::serialize(&rlp);
/// Broadcasts a raw RLP encoded transaction via the `eth_sendRawTransaction` API
pub async fn send_raw_transaction(&self, tx: &Transaction) -> Result<TxHash, P::Error> {
let rlp = utils::serialize(&tx.rlp());
self.0.request("eth_sendRawTransaction", Some(rlp)).await
}

View File

@ -1,31 +1,45 @@
use crate::{
providers::{JsonRpcClient, Provider},
signers::Signer,
types::{Transaction, TxHash, UnsignedTransaction},
types::{Address, Transaction, UnsignedTransaction},
};
use std::ops::Deref;
#[derive(Clone, Debug)]
pub struct Client<'a, S, P> {
pub provider: &'a Provider<P>,
pub signer: S,
pub(crate) provider: &'a Provider<P>,
pub(crate) signer: S,
}
impl<'a, S: Signer, P: JsonRpcClient> Client<'a, S, P> {
pub async fn send_transaction(&self, tx: UnsignedTransaction) -> Result<Transaction, P::Error> {
/// Signs the transaction and then broadcasts its RLP encoding via the `eth_sendRawTransaction`
/// API
pub async fn sign_and_send_transaction(
&self,
tx: UnsignedTransaction,
) -> Result<Transaction, P::Error> {
// sign the transaction
let signed_tx = self.signer.sign_transaction(tx.clone());
// broadcast it
self.provider.send_raw_transaction(&signed_tx.rlp()).await?;
self.provider.send_raw_transaction(&signed_tx).await?;
Ok(signed_tx)
}
// TODO: Forward all other calls to the provider
pub async fn get_transaction<T: Send + Sync + Into<TxHash>>(
&self,
hash: T,
) -> Result<Transaction, P::Error> {
self.provider.get_transaction(hash).await
pub fn address(&self) -> Address {
self.signer.address()
}
}
// Abuse Deref to use the Provider's methods without re-writing everything.
// This is an anti-pattern and should not be encouraged, but this improves the UX while
// keeping the LoC low
impl<'a, S, P> Deref for Client<'a, S, P> {
type Target = &'a Provider<P>;
fn deref(&self) -> &Self::Target {
&self.provider
}
}

View File

@ -9,7 +9,7 @@ pub use wallet::Wallet;
mod client;
pub(crate) use client::Client;
use crate::types::{Signature, Transaction, UnsignedTransaction};
use crate::types::{Address, Signature, Transaction, UnsignedTransaction};
/// Trait for signing transactions and messages
///
@ -20,4 +20,7 @@ pub trait Signer {
/// Signs the transaction
fn sign_transaction(&self, message: UnsignedTransaction) -> Transaction;
/// Returns the signer's Ethereum Address
fn address(&self) -> Address;
}

View File

@ -24,6 +24,10 @@ impl<'a, N: Network> Signer for Wallet<N> {
fn sign_transaction(&self, tx: UnsignedTransaction) -> Transaction {
self.private_key.sign_transaction(tx, N::CHAIN_ID)
}
fn address(&self) -> Address {
self.address
}
}
impl<N: Network> Wallet<N> {