enhance signer middleware to automatically switch legacy (#1832)

This commit is contained in:
Kristian Gaylord 2022-11-07 15:27:45 -05:00 committed by GitHub
parent 9797e9a83b
commit 22fae3f8e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 83 additions and 2 deletions

View File

@ -1,9 +1,10 @@
use ethers_core::types::{ use ethers_core::types::{
transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
Address, BlockId, Bytes, Signature, U256, Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256,
}; };
use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction}; use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction};
use ethers_signers::Signer; use ethers_signers::Signer;
use std::convert::TryFrom;
use async_trait::async_trait; use async_trait::async_trait;
use thiserror::Error; use thiserror::Error;
@ -251,6 +252,18 @@ where
tx.set_chain_id(chain_id); tx.set_chain_id(chain_id);
} }
// If a chain_id is matched to a known chain that doesn't support EIP-1559, automatically
// change transaction to be Legacy type.
if let Some(chain_id) = tx.chain_id() {
let chain = Chain::try_from(chain_id.as_u64());
if chain.unwrap_or_default().is_legacy() {
if let TypedTransaction::Eip1559(inner) = tx {
let tx_req: TransactionRequest = inner.clone().into();
*tx = TypedTransaction::Legacy(tx_req);
}
}
}
let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?; let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?;
tx.set_nonce(nonce); tx.set_nonce(nonce);
self.inner() self.inner()
@ -338,7 +351,7 @@ where
mod tests { mod tests {
use super::*; use super::*;
use ethers_core::{ use ethers_core::{
types::TransactionRequest, types::{Eip1559TransactionRequest, TransactionRequest},
utils::{self, keccak256, Anvil}, utils::{self, keccak256, Anvil},
}; };
use ethers_providers::Provider; use ethers_providers::Provider;
@ -503,4 +516,72 @@ mod tests {
let tx = client.get_transaction(hash).await.unwrap().unwrap(); let tx = client.get_transaction(hash).await.unwrap().unwrap();
assert_eq!(tx.from, acc); assert_eq!(tx.from, acc);
} }
#[tokio::test]
async fn converts_tx_to_legacy_to_match_chain() {
let eip1559 = Eip1559TransactionRequest {
from: None,
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
value: Some(1_000_000_000.into()),
gas: Some(2_000_000.into()),
nonce: Some(U256::zero()),
access_list: Default::default(),
max_priority_fee_per_gas: None,
data: None,
chain_id: None,
max_fee_per_gas: None,
};
let mut tx = TypedTransaction::Eip1559(eip1559);
let chain_id = 10u64; // optimism does not support EIP-1559
// Signer middlewares now rely on a working provider which it can query the chain id from,
// so we make sure Anvil is started with the chain id that the expected tx was signed
// with
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
let provider = Provider::try_from(anvil.endpoint()).unwrap();
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
.parse::<LocalWallet>()
.unwrap()
.with_chain_id(chain_id);
let client = SignerMiddleware::new(provider, key);
client.fill_transaction(&mut tx, None).await.unwrap();
assert!(tx.as_eip1559_ref().is_none());
assert_eq!(tx, TypedTransaction::Legacy(tx.as_legacy_ref().unwrap().clone()));
}
#[tokio::test]
async fn does_not_convert_to_legacy_for_eip1559_chain() {
let eip1559 = Eip1559TransactionRequest {
from: None,
to: Some("F0109fC8DF283027b6285cc889F5aA624EaC1F55".parse::<Address>().unwrap().into()),
value: Some(1_000_000_000.into()),
gas: Some(2_000_000.into()),
nonce: Some(U256::zero()),
access_list: Default::default(),
max_priority_fee_per_gas: None,
data: None,
chain_id: None,
max_fee_per_gas: None,
};
let mut tx = TypedTransaction::Eip1559(eip1559);
let chain_id = 1u64; // eth main supports EIP-1559
// Signer middlewares now rely on a working provider which it can query the chain id from,
// so we make sure Anvil is started with the chain id that the expected tx was signed
// with
let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
let provider = Provider::try_from(anvil.endpoint()).unwrap();
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
.parse::<LocalWallet>()
.unwrap()
.with_chain_id(chain_id);
let client = SignerMiddleware::new(provider, key);
client.fill_transaction(&mut tx, None).await.unwrap();
assert!(tx.as_legacy_ref().is_none());
assert_eq!(tx, TypedTransaction::Eip1559(tx.as_eip1559_ref().unwrap().clone()));
}
} }