diff --git a/ethers-middleware/src/signer.rs b/ethers-middleware/src/signer.rs index f5d58e58..1d7c4be4 100644 --- a/ethers-middleware/src/signer.rs +++ b/ethers-middleware/src/signer.rs @@ -167,6 +167,14 @@ where true } + async fn sign_transaction( + &self, + tx: &TypedTransaction, + _: Address, + ) -> Result { + Ok(self.signer.sign_transaction(tx).await.map_err(SignerMiddlewareError::SignerError)?) + } + /// Helper for filling a transaction's nonce using the wallet async fn fill_transaction( &self, diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 215619d1..3d735a8f 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -315,7 +315,7 @@ pub trait Middleware: Sync + Send + Debug { r }) .map(|req| async move { - self.sign(req.rlp(chain_id), &self.default_sender().unwrap_or_default()) + self.sign_transaction(&req, self.default_sender().unwrap_or_default()) .await .map(|sig| req.rlp_signed(chain_id, &sig)) }) @@ -456,6 +456,15 @@ pub trait Middleware: Sync + Send + Debug { self.inner().sign(data, from).await.map_err(FromErr::from) } + /// Sign a transaction via RPC call + async fn sign_transaction( + &self, + tx: &TypedTransaction, + from: Address, + ) -> Result { + self.inner().sign_transaction(tx, from).await.map_err(FromErr::from) + } + ////// Contract state async fn get_logs(&self, filter: &Filter) -> Result, Self::Error> { diff --git a/ethers-providers/src/pending_escalator.rs b/ethers-providers/src/pending_escalator.rs index a09fa53e..e1893a4f 100644 --- a/ethers-providers/src/pending_escalator.rs +++ b/ethers-providers/src/pending_escalator.rs @@ -140,11 +140,18 @@ macro_rules! poll_broadcast_fut { check_all_receipts!($cx, $this); } Poll::Ready(Err(e)) => { - tracing::error!( - error = ?e, - "Error during transaction broadcast" - ); - completed!($this, Err(e)); + // kludge. Prevents erroring on "nonce too low" which indicates + // a previous escalation confirmed during this broadcast attempt + if format!("{}", e).contains("nonce too low") { + check_all_receipts!($cx, $this); + } else { + tracing::error!( + error = ?e, + "Error during transaction broadcast" + ); + + completed!($this, Err(e)); + } } Poll::Pending => return Poll::Pending, } diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 28da3797..72125e53 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -125,6 +125,9 @@ pub enum ProviderError { #[error("unsupported node client")] UnsupportedNodeClient, + + #[error("Attempted to sign a transaction with no available signer. Hint: did you mean to use a SignerMiddleware?")] + SignerUnavailable, } /// Types of filters supported by the JSON-RPC. @@ -517,6 +520,15 @@ impl Middleware for Provider

{ .map_err(|e| ProviderError::CustomError(e.to_string()))?) } + /// Sign a transaction via RPC call + async fn sign_transaction( + &self, + _tx: &TypedTransaction, + _from: Address, + ) -> Result { + Err(ProviderError::SignerUnavailable).map_err(FromErr::from) + } + ////// Contract state /// Returns an array (possibly empty) of logs that match the filter