|
1 | 1 | use ethers_core::types::{
|
2 | 2 | transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
|
3 |
| - Address, BlockId, Bytes, Signature, U256, |
| 3 | + Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256, |
4 | 4 | };
|
5 | 5 | use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction};
|
6 | 6 | use ethers_signers::Signer;
|
| 7 | +use std::convert::TryFrom; |
7 | 8 |
|
8 | 9 | use async_trait::async_trait;
|
9 | 10 | use thiserror::Error;
|
@@ -251,6 +252,18 @@ where
|
251 | 252 | tx.set_chain_id(chain_id);
|
252 | 253 | }
|
253 | 254 |
|
| 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 | + |
254 | 267 | let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?;
|
255 | 268 | tx.set_nonce(nonce);
|
256 | 269 | self.inner()
|
@@ -338,7 +351,7 @@ where
|
338 | 351 | mod tests {
|
339 | 352 | use super::*;
|
340 | 353 | use ethers_core::{
|
341 |
| - types::TransactionRequest, |
| 354 | + types::{Eip1559TransactionRequest, TransactionRequest}, |
342 | 355 | utils::{self, keccak256, Anvil},
|
343 | 356 | };
|
344 | 357 | use ethers_providers::Provider;
|
@@ -503,4 +516,72 @@ mod tests {
|
503 | 516 | let tx = client.get_transaction(hash).await.unwrap().unwrap();
|
504 | 517 | assert_eq!(tx.from, acc);
|
505 | 518 | }
|
| 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 | + } |
506 | 587 | }
|
0 commit comments