|
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,24 @@ 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 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 | + |
254 | 273 | let nonce = maybe(tx.nonce().cloned(), self.get_transaction_count(from, block)).await?;
|
255 | 274 | tx.set_nonce(nonce);
|
256 | 275 | self.inner()
|
@@ -338,7 +357,7 @@ where
|
338 | 357 | mod tests {
|
339 | 358 | use super::*;
|
340 | 359 | use ethers_core::{
|
341 |
| - types::TransactionRequest, |
| 360 | + types::{Eip1559TransactionRequest, TransactionRequest}, |
342 | 361 | utils::{self, keccak256, Anvil},
|
343 | 362 | };
|
344 | 363 | use ethers_providers::Provider;
|
@@ -503,4 +522,72 @@ mod tests {
|
503 | 522 | let tx = client.get_transaction(hash).await.unwrap().unwrap();
|
504 | 523 | assert_eq!(tx.from, acc);
|
505 | 524 | }
|
| 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 | + } |
506 | 593 | }
|
0 commit comments