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

Commit 35a1a56

Browse files
committed
enhance signer middleware to automatically switch legacy
1 parent 14e0388 commit 35a1a56

File tree

1 file changed

+89
-2
lines changed

1 file changed

+89
-2
lines changed

Diff for: ethers-middleware/src/signer.rs

+89-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use ethers_core::types::{
22
transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
3-
Address, BlockId, Bytes, Signature, U256,
3+
Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256,
44
};
55
use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction};
66
use ethers_signers::Signer;
7+
use std::convert::TryFrom;
78

89
use async_trait::async_trait;
910
use thiserror::Error;
@@ -251,6 +252,24 @@ where
251252
tx.set_chain_id(chain_id);
252253
}
253254

255+
// If a chain_id is matched to a known chain that doesn't support EIP-1559, automatically
256+
// change transaction to be Legacy type.
257+
if tx.chain_id().is_some() {
258+
let tx_chain_id = tx.chain_id().unwrap(); // safe unwrap after is_some check above
259+
let chain = Chain::try_from(tx_chain_id.as_u64());
260+
if chain.is_ok() && chain.unwrap().is_legacy() {
261+
// safe unwrap after is_ok check
262+
let legacy_tx = match tx.clone() {
263+
TypedTransaction::Eip1559(inner) => {
264+
let i_tx: TransactionRequest = inner.into();
265+
TypedTransaction::Legacy(i_tx)
266+
}
267+
other => other,
268+
};
269+
*tx = legacy_tx;
270+
}
271+
}
272+
254273
let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?;
255274
tx.set_nonce(nonce);
256275
self.inner()
@@ -338,7 +357,7 @@ where
338357
mod tests {
339358
use super::*;
340359
use ethers_core::{
341-
types::TransactionRequest,
360+
types::{Eip1559TransactionRequest, TransactionRequest},
342361
utils::{self, keccak256, Anvil},
343362
};
344363
use ethers_providers::Provider;
@@ -503,4 +522,72 @@ mod tests {
503522
let tx = client.get_transaction(hash).await.unwrap().unwrap();
504523
assert_eq!(tx.from, acc);
505524
}
525+
526+
#[tokio::test]
527+
async fn converts_tx_to_legacy_to_match_chain() {
528+
let eip1559 = Eip1559TransactionRequest {
529+
from: None,
530+
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
531+
value: Some(1_000_000_000.into()),
532+
gas: Some(2_000_000.into()),
533+
nonce: Some(U256::zero()),
534+
access_list: Default::default(),
535+
max_priority_fee_per_gas: None,
536+
data: None,
537+
chain_id: None,
538+
max_fee_per_gas: None,
539+
};
540+
let mut tx = TypedTransaction::Eip1559(eip1559);
541+
542+
let chain_id = 10u64; // optimism does not support EIP-1559
543+
544+
// Signer middlewares now rely on a working provider which it can query the chain id from,
545+
// so we make sure Anvil is started with the chain id that the expected tx was signed
546+
// with
547+
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
548+
let provider = Provider::try_from(anvil.endpoint()).unwrap();
549+
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
550+
.parse::<LocalWallet>()
551+
.unwrap()
552+
.with_chain_id(chain_id);
553+
let client = SignerMiddleware::new(provider, key);
554+
client.fill_transaction(&mut tx, None).await.unwrap();
555+
556+
assert!(tx.as_eip1559_ref().is_none());
557+
assert_eq!(tx, TypedTransaction::Legacy(tx.as_legacy_ref().unwrap().clone()));
558+
}
559+
560+
#[tokio::test]
561+
async fn does_not_convert_to_legacy_for_eip1559_chain() {
562+
let eip1559 = Eip1559TransactionRequest {
563+
from: None,
564+
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
565+
value: Some(1_000_000_000.into()),
566+
gas: Some(2_000_000.into()),
567+
nonce: Some(U256::zero()),
568+
access_list: Default::default(),
569+
max_priority_fee_per_gas: None,
570+
data: None,
571+
chain_id: None,
572+
max_fee_per_gas: None,
573+
};
574+
let mut tx = TypedTransaction::Eip1559(eip1559);
575+
576+
let chain_id = 1u64; // eth main supports EIP-1559
577+
578+
// Signer middlewares now rely on a working provider which it can query the chain id from,
579+
// so we make sure Anvil is started with the chain id that the expected tx was signed
580+
// with
581+
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
582+
let provider = Provider::try_from(anvil.endpoint()).unwrap();
583+
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
584+
.parse::<LocalWallet>()
585+
.unwrap()
586+
.with_chain_id(chain_id);
587+
let client = SignerMiddleware::new(provider, key);
588+
client.fill_transaction(&mut tx, None).await.unwrap();
589+
590+
assert!(tx.as_legacy_ref().is_none());
591+
assert_eq!(tx, TypedTransaction::Eip1559(tx.as_eip1559_ref().unwrap().clone()));
592+
}
506593
}

0 commit comments

Comments
 (0)