Skip to content

Commit 8c47eb4

Browse files
kristian1108hexiaoyuan
authored andcommitted
enhance signer middleware to automatically switch legacy (gakonst#1832)
1 parent 62cd735 commit 8c47eb4

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

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

+83-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,18 @@ 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 let Some(chain_id) = tx.chain_id() {
258+
let chain = Chain::try_from(chain_id.as_u64());
259+
if chain.unwrap_or_default().is_legacy() {
260+
if let TypedTransaction::Eip1559(inner) = tx {
261+
let tx_req: TransactionRequest = inner.clone().into();
262+
*tx = TypedTransaction::Legacy(tx_req);
263+
}
264+
}
265+
}
266+
254267
let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?;
255268
tx.set_nonce(nonce);
256269
self.inner()
@@ -338,7 +351,7 @@ where
338351
mod tests {
339352
use super::*;
340353
use ethers_core::{
341-
types::TransactionRequest,
354+
types::{Eip1559TransactionRequest, TransactionRequest},
342355
utils::{self, keccak256, Anvil},
343356
};
344357
use ethers_providers::Provider;
@@ -503,4 +516,72 @@ mod tests {
503516
let tx = client.get_transaction(hash).await.unwrap().unwrap();
504517
assert_eq!(tx.from, acc);
505518
}
519+
520+
#[tokio::test]
521+
async fn converts_tx_to_legacy_to_match_chain() {
522+
let eip1559 = Eip1559TransactionRequest {
523+
from: None,
524+
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
525+
value: Some(1_000_000_000.into()),
526+
gas: Some(2_000_000.into()),
527+
nonce: Some(U256::zero()),
528+
access_list: Default::default(),
529+
max_priority_fee_per_gas: None,
530+
data: None,
531+
chain_id: None,
532+
max_fee_per_gas: None,
533+
};
534+
let mut tx = TypedTransaction::Eip1559(eip1559);
535+
536+
let chain_id = 10u64; // optimism does not support EIP-1559
537+
538+
// Signer middlewares now rely on a working provider which it can query the chain id from,
539+
// so we make sure Anvil is started with the chain id that the expected tx was signed
540+
// with
541+
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
542+
let provider = Provider::try_from(anvil.endpoint()).unwrap();
543+
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
544+
.parse::<LocalWallet>()
545+
.unwrap()
546+
.with_chain_id(chain_id);
547+
let client = SignerMiddleware::new(provider, key);
548+
client.fill_transaction(&mut tx, None).await.unwrap();
549+
550+
assert!(tx.as_eip1559_ref().is_none());
551+
assert_eq!(tx, TypedTransaction::Legacy(tx.as_legacy_ref().unwrap().clone()));
552+
}
553+
554+
#[tokio::test]
555+
async fn does_not_convert_to_legacy_for_eip1559_chain() {
556+
let eip1559 = Eip1559TransactionRequest {
557+
from: None,
558+
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
559+
value: Some(1_000_000_000.into()),
560+
gas: Some(2_000_000.into()),
561+
nonce: Some(U256::zero()),
562+
access_list: Default::default(),
563+
max_priority_fee_per_gas: None,
564+
data: None,
565+
chain_id: None,
566+
max_fee_per_gas: None,
567+
};
568+
let mut tx = TypedTransaction::Eip1559(eip1559);
569+
570+
let chain_id = 1u64; // eth main supports EIP-1559
571+
572+
// Signer middlewares now rely on a working provider which it can query the chain id from,
573+
// so we make sure Anvil is started with the chain id that the expected tx was signed
574+
// with
575+
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
576+
let provider = Provider::try_from(anvil.endpoint()).unwrap();
577+
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
578+
.parse::<LocalWallet>()
579+
.unwrap()
580+
.with_chain_id(chain_id);
581+
let client = SignerMiddleware::new(provider, key);
582+
client.fill_transaction(&mut tx, None).await.unwrap();
583+
584+
assert!(tx.as_legacy_ref().is_none());
585+
assert_eq!(tx, TypedTransaction::Eip1559(tx.as_eip1559_ref().unwrap().clone()));
586+
}
506587
}

0 commit comments

Comments
 (0)