From 8f24277bca53e02b0d05d3c5a29aa6a6829d049b Mon Sep 17 00:00:00 2001 From: Nima Rasooli <110225819+EmperorOrokuSaki@users.noreply.github.com> Date: Wed, 24 Apr 2024 02:57:55 +0400 Subject: [PATCH] [Blocked] Update TransactionRequest's `to` field to TxKind (#553) * feat: change the `to` field type to TxKind, update From accordingly * refactor: update builder functions to include `to` checks. * feat: add as_create(), with_call(), and deploy_code() * refactor: remove error lines * feat: with_call impl. * feat: add the methods to the builder trait, update code that was broken. * test: update tests. * nits: reordering and default impls * fix: some test compilation * nit: fmt * lint: clippy * test: fix tests * refactor: kind vs to * feat: new_raw_deploy and generic input * doc: add note re sol usage * fix: type inference in test * chore: update core * docs --------- Co-authored-by: James Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- Cargo.toml | 11 ++- crates/contract/src/call.rs | 52 +++++++++---- crates/eips/src/eip6110.rs | 2 + crates/network/Cargo.toml | 1 + crates/network/src/any/builder.rs | 15 ++-- crates/network/src/ethereum/builder.rs | 39 +++++----- crates/network/src/transaction/builder.rs | 75 +++++++++++++++++-- crates/provider/src/debug.rs | 2 +- crates/provider/src/fillers/gas.rs | 6 +- crates/provider/src/fillers/nonce.rs | 4 +- crates/provider/src/fillers/signer.rs | 2 +- crates/provider/src/provider.rs | 4 +- crates/rpc-types/src/eth/block.rs | 2 + crates/rpc-types/src/eth/transaction/mod.rs | 6 +- .../rpc-types/src/eth/transaction/request.rs | 37 ++++++--- 15 files changed, 187 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4bfe20b35e0..7167f3e687f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,12 +46,11 @@ alloy-transport-ws = { version = "0.1.0", default-features = false, path = "crat test-utils = { version = "0.1.0", default-features = false, path = "crates/internal-test-utils", package = "alloy-internal-test-utils" } -alloy-core = { version = "0.7.0", default-features = false } -alloy-dyn-abi = { version = "0.7.0", default-features = false } -alloy-json-abi = { version = "0.7.0", default-features = false } -alloy-primitives = { version = "0.7.0", default-features = false } -alloy-sol-types = { version = "0.7.0", default-features = false } -alloy-chains = {version = "0.1.15", default-features = false} +alloy-core = { version = "0.7.1", default-features = false } +alloy-dyn-abi = { version = "0.7.1", default-features = false } +alloy-json-abi = { version = "0.7.1", default-features = false } +alloy-primitives = { version = "0.7.1", default-features = false } +alloy-sol-types = { version = "0.7.1", default-features = false } alloy-rlp = { version = "0.3", default-features = false } diff --git a/crates/contract/src/call.rs b/crates/contract/src/call.rs index b76dfbd0ca4..515e224e129 100644 --- a/crates/contract/src/call.rs +++ b/crates/contract/src/call.rs @@ -201,14 +201,12 @@ pub struct CallBuilder { // See [`ContractInstance`]. impl, N: Network> DynCallBuilder { - pub(crate) fn new_dyn( - provider: P, - function: &Function, - args: &[DynSolValue], - address: &Address, - ) -> Result { - Ok(Self::new_inner(provider, function.abi_encode_input(args)?.into(), function.clone()) - .to(Some(*address))) + pub(crate) fn new_dyn(provider: P, function: &Function, args: &[DynSolValue]) -> Result { + Ok(Self::new_inner_call( + provider, + function.abi_encode_input(args)?.into(), + function.clone(), + )) } /// Clears the decoder, returning a raw call builder. @@ -232,7 +230,7 @@ impl<'a, T: Transport + Clone, P: Provider, C: SolCall, N: Network> // `sol!` macro constructor, see `#[sol(rpc)]`. Not public API. // NOTE: please avoid changing this function due to its use in the `sol!` macro. pub fn new_sol(provider: &'a P, address: &Address, call: &C) -> Self { - Self::new_inner(provider, call.abi_encode().into(), PhantomData::).to(Some(*address)) + Self::new_inner_call(provider, call.abi_encode().into(), PhantomData::).to(*address) } } @@ -258,12 +256,32 @@ impl, N: Network> RawCallBuilder Self { - Self::new_inner(provider, input, ()) + Self::new_inner_call(provider, input, ()) + } + + /// Creates a new call builder with the provided provider and contract deploy code. + /// + /// Will not decode the output of the call, meaning that [`call`](Self::call) will behave the + /// same as [`call_raw`](Self::call_raw). + // NOTE: please avoid changing this function due to its use in the `sol!` macro. + pub fn new_raw_deploy(provider: P, input: Bytes) -> Self { + Self::new_inner_deploy(provider, input, ()) } } impl, D: CallDecoder, N: Network> CallBuilder { - fn new_inner(provider: P, input: Bytes, decoder: D) -> Self { + fn new_inner_deploy(provider: P, input: Bytes, decoder: D) -> Self { + Self { + request: ::default().with_deploy_code(input), + decoder, + provider, + block: BlockId::default(), + state: None, + transport: PhantomData, + } + } + + fn new_inner_call(provider: P, input: Bytes, decoder: D) -> Self { Self { request: ::default().with_input(input), decoder, @@ -280,9 +298,15 @@ impl, D: CallDecoder, N: Network> CallBu self } + /// Sets the transaction request to the provided tx kind. + pub fn kind(mut self, to: TxKind) -> Self { + self.request.set_kind(to); + self + } + /// Sets the `to` field in the transaction to the provided address. - pub fn to(mut self, to: Option
) -> Self { - self.request.set_to(to.into()); + pub fn to(mut self, to: Address) -> Self { + self.request.set_to(to); self } @@ -419,7 +443,7 @@ impl, D: CallDecoder, N: Network> CallBu /// Note that the deployment address can be pre-calculated if the `from` address and `nonce` are /// known using [`calculate_create_address`](Self::calculate_create_address). pub async fn deploy(&self) -> Result
{ - if !self.request.to().is_some_and(|to| to.is_create()) { + if !self.request.kind().is_some_and(|to| to.is_create()) { return Err(Error::NotADeploymentTransaction); } let pending_tx = self.send().await?; diff --git a/crates/eips/src/eip6110.rs b/crates/eips/src/eip6110.rs index 59795cddab7..bfc9819dfb5 100644 --- a/crates/eips/src/eip6110.rs +++ b/crates/eips/src/eip6110.rs @@ -4,6 +4,8 @@ //! //! Provides validator deposits as a list of deposit operations added to the Execution Layer block. +#![allow(unknown_lints, non_local_definitions)] + use alloy_primitives::{address, Address, FixedBytes, B256}; use alloy_rlp::{RlpDecodable, RlpEncodable}; diff --git a/crates/network/Cargo.toml b/crates/network/Cargo.toml index 9a2e7953f6f..ed09faa6d26 100644 --- a/crates/network/Cargo.toml +++ b/crates/network/Cargo.toml @@ -18,6 +18,7 @@ alloy-json-rpc.workspace = true alloy-primitives.workspace = true alloy-rpc-types.workspace = true alloy-signer.workspace = true +alloy-sol-types.workspace = true async-trait.workspace = true futures-utils-wasm.workspace = true diff --git a/crates/network/src/any/builder.rs b/crates/network/src/any/builder.rs index 19ba1ff5c6e..6607fc5815c 100644 --- a/crates/network/src/any/builder.rs +++ b/crates/network/src/any/builder.rs @@ -1,6 +1,7 @@ use std::ops::{Deref, DerefMut}; use alloy_consensus::BlobTransactionSidecar; +use alloy_primitives::Bytes; use alloy_rpc_types::{AccessList, TransactionRequest, WithOtherFields}; use crate::{any::AnyNetwork, BuildResult, Network, TransactionBuilder, TransactionBuilderError}; @@ -26,7 +27,7 @@ impl TransactionBuilder for WithOtherFields { self.deref().input() } - fn set_input(&mut self, input: alloy_primitives::Bytes) { + fn set_input>(&mut self, input: T) { self.deref_mut().set_input(input); } @@ -38,12 +39,16 @@ impl TransactionBuilder for WithOtherFields { self.deref_mut().set_from(from); } - fn to(&self) -> Option { - self.deref().to() + fn kind(&self) -> Option { + self.deref().kind() } - fn set_to(&mut self, to: alloy_primitives::TxKind) { - self.deref_mut().set_to(to) + fn clear_kind(&mut self) { + self.deref_mut().clear_kind() + } + + fn set_kind(&mut self, kind: alloy_primitives::TxKind) { + self.deref_mut().set_kind(kind) } fn value(&self) -> Option { diff --git a/crates/network/src/ethereum/builder.rs b/crates/network/src/ethereum/builder.rs index a86211c0d8a..3890e8905cb 100644 --- a/crates/network/src/ethereum/builder.rs +++ b/crates/network/src/ethereum/builder.rs @@ -26,8 +26,8 @@ impl TransactionBuilder for TransactionRequest { self.input.input() } - fn set_input(&mut self, input: Bytes) { - self.input.input = Some(input); + fn set_input>(&mut self, input: T) { + self.input.input = Some(input.into()); } fn from(&self) -> Option
{ @@ -38,15 +38,16 @@ impl TransactionBuilder for TransactionRequest { self.from = Some(from); } - fn to(&self) -> Option { - self.to.map(TxKind::Call).or(Some(TxKind::Create)) + fn kind(&self) -> Option { + self.to } - fn set_to(&mut self, to: TxKind) { - match to { - TxKind::Create => self.to = None, - TxKind::Call(to) => self.to = Some(to), - } + fn set_kind(&mut self, kind: TxKind) { + self.to = Some(kind); + } + + fn clear_kind(&mut self) { + self.to = None; } fn value(&self) -> Option { @@ -193,7 +194,7 @@ mod tests { .with_gas_limit(0) .with_max_fee_per_gas(0) .with_max_priority_fee_per_gas(0) - .with_to(Address::ZERO.into()) + .with_to(Address::ZERO) .with_blob_sidecar(BlobTransactionSidecar::default()) .with_max_fee_per_blob_gas(0); @@ -213,7 +214,7 @@ mod tests { .with_gas_limit(0) .with_max_fee_per_gas(0) .with_max_priority_fee_per_gas(0) - .with_to(Address::ZERO.into()) + .with_to(Address::ZERO) .with_gas_price(0) .access_list(AccessList::default()); @@ -229,14 +230,13 @@ mod tests { .with_gas_limit(0) .with_max_fee_per_gas(0) .with_max_priority_fee_per_gas(0) - .with_to(Address::ZERO.into()); + .with_to(Address::ZERO); let tx = request.clone().build_unsigned().unwrap(); assert!(matches!(tx, TypedTransaction::Eip1559(_))); let request = request.with_gas_price(0); - dbg!(request.preferred_type()); let tx = request.build_unsigned().unwrap(); assert!(matches!(tx, TypedTransaction::Legacy(_))); } @@ -263,7 +263,8 @@ mod tests { }; assert_eq!(tx_type, TxType::Legacy); - assert_eq!(errors.len(), 2); + assert_eq!(errors.len(), 3); + assert!(errors.contains(&"to")); assert!(errors.contains(&"nonce")); assert!(errors.contains(&"gas_limit")); } @@ -279,7 +280,8 @@ mod tests { }; assert_eq!(tx_type, TxType::Eip1559); - assert_eq!(errors.len(), 4); + assert_eq!(errors.len(), 5); + assert!(errors.contains(&"to")); assert!(errors.contains(&"nonce")); assert!(errors.contains(&"gas_limit")); assert!(errors.contains(&"max_priority_fee_per_gas")); @@ -297,7 +299,8 @@ mod tests { }; assert_eq!(tx_type, TxType::Eip2930); - assert_eq!(errors.len(), 3); + assert_eq!(errors.len(), 4); + assert!(errors.contains(&"to")); assert!(errors.contains(&"nonce")); assert!(errors.contains(&"gas_limit")); assert!(errors.contains(&"gas_price")); @@ -315,8 +318,8 @@ mod tests { }; assert_eq!(tx_type, TxType::Eip4844); - dbg!(&errors); - assert_eq!(errors.len(), 6); + assert_eq!(errors.len(), 7); + assert!(errors.contains(&"to")); assert!(errors.contains(&"nonce")); assert!(errors.contains(&"gas_limit")); assert!(errors.contains(&"max_priority_fee_per_gas")); diff --git a/crates/network/src/transaction/builder.rs b/crates/network/src/transaction/builder.rs index 1941de63088..34c13c258a3 100644 --- a/crates/network/src/transaction/builder.rs +++ b/crates/network/src/transaction/builder.rs @@ -3,6 +3,7 @@ use crate::Network; use alloy_consensus::BlobTransactionSidecar; use alloy_primitives::{Address, Bytes, ChainId, TxKind, U256}; use alloy_rpc_types::AccessList; +use alloy_sol_types::SolCall; use futures_utils_wasm::impl_future; /// Result type for transaction builders @@ -78,10 +79,10 @@ pub trait TransactionBuilder: Default + Sized + Send + Sync + 'stati fn input(&self) -> Option<&Bytes>; /// Set the input data for the transaction. - fn set_input(&mut self, input: Bytes); + fn set_input>(&mut self, input: T); /// Builder-pattern method for setting the input data. - fn with_input(mut self, input: Bytes) -> Self { + fn with_input>(mut self, input: T) -> Self { self.set_input(input); self } @@ -98,24 +99,86 @@ pub trait TransactionBuilder: Default + Sized + Send + Sync + 'stati self } + /// Get the kind of transaction. + fn kind(&self) -> Option; + + /// Clear the kind of transaction. + fn clear_kind(&mut self); + + /// Set the kind of transaction. + fn set_kind(&mut self, kind: alloy_primitives::TxKind); + + /// Builder-pattern method for setting the kind of transaction. + fn with_kind(mut self, kind: alloy_primitives::TxKind) -> Self { + self.set_kind(kind); + self + } + /// Get the recipient for the transaction. - fn to(&self) -> Option; + fn to(&self) -> Option
{ + if let Some(TxKind::Call(addr)) = self.kind() { + return Some(addr); + } + None + } /// Set the recipient for the transaction. - fn set_to(&mut self, to: TxKind); + fn set_to(&mut self, to: Address) { + self.set_kind(TxKind::Call(to)); + } /// Builder-pattern method for setting the recipient. - fn with_to(mut self, to: TxKind) -> Self { + fn with_to(mut self, to: Address) -> Self { self.set_to(to); self } + /// Set the `to` field to a create call. + fn set_create(&mut self) { + self.set_kind(TxKind::Create); + } + + /// Set the `to` field to a create call. + fn into_create(mut self) -> Self { + self.set_create(); + self + } + + /// Deploy the code by making a create call with data. This will set the + /// `to` field to [`TxKind::Create`]. + fn set_deploy_code>(&mut self, code: T) { + self.set_input(code.into()); + self.set_create() + } + + /// Deploy the code by making a create call with data. This will set the + /// `to` field to [`TxKind::Create`]. + fn with_deploy_code>(mut self, code: T) -> Self { + self.set_deploy_code(code); + self + } + + /// Set the data field to a contract call. This will clear the `to` field + /// if it is set to [`TxKind::Create`]. + fn set_call(&mut self, t: &T) { + self.set_input(t.abi_encode()); + if matches!(self.kind(), Some(TxKind::Create)) { + self.clear_kind(); + } + } + + /// Make a contract call with data. + fn with_call(mut self, t: &T) -> Self { + self.set_call(t); + self + } + /// Calculates the address that will be created by the transaction, if any. /// /// Returns `None` if the transaction is not a contract creation (the `to` field is set), or if /// the `from` or `nonce` fields are not set. fn calculate_create_address(&self) -> Option
{ - if !self.to().is_some_and(|to| to.is_create()) { + if !self.kind().is_some_and(|to| to.is_create()) { return None; } let from = self.from()?; diff --git a/crates/provider/src/debug.rs b/crates/provider/src/debug.rs index 65078b3e664..fce19695647 100644 --- a/crates/provider/src/debug.rs +++ b/crates/provider/src/debug.rs @@ -191,7 +191,7 @@ mod test { let gas_price = provider.get_gas_price().await.unwrap(); let tx = TransactionRequest::default() .from(from) - .with_input("0xdeadbeef".into()) + .with_input("0xdeadbeef") .max_fee_per_gas(gas_price + 1) .max_priority_fee_per_gas(gas_price + 1); diff --git a/crates/provider/src/fillers/gas.rs b/crates/provider/src/fillers/gas.rs index c3327c4ee4a..600971ae86f 100644 --- a/crates/provider/src/fillers/gas.rs +++ b/crates/provider/src/fillers/gas.rs @@ -266,7 +266,7 @@ mod tests { let tx = TransactionRequest { from: Some(anvil.addresses()[0]), value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), chain_id: Some(31337), ..Default::default() }; @@ -288,7 +288,7 @@ mod tests { let tx = TransactionRequest { from: Some(anvil.addresses()[0]), value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), gas_price: Some(gas_price), ..Default::default() }; @@ -311,7 +311,7 @@ mod tests { let tx = TransactionRequest { from: Some(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266")), value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), // access list forces legacy gassing access_list: Some(vec![Default::default()].into()), ..Default::default() diff --git a/crates/provider/src/fillers/nonce.rs b/crates/provider/src/fillers/nonce.rs index ab4ba18cb92..a0c6c239045 100644 --- a/crates/provider/src/fillers/nonce.rs +++ b/crates/provider/src/fillers/nonce.rs @@ -126,7 +126,7 @@ mod tests { let tx = TransactionRequest { value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), gas_price: Some(20e9 as u128), gas: Some(21000), ..Default::default() @@ -145,7 +145,7 @@ mod tests { let tx = TransactionRequest { from: Some(from), value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), gas_price: Some(20e9 as u128), gas: Some(21000), ..Default::default() diff --git a/crates/provider/src/fillers/signer.rs b/crates/provider/src/fillers/signer.rs index c1e04c525d4..979658dbd3f 100644 --- a/crates/provider/src/fillers/signer.rs +++ b/crates/provider/src/fillers/signer.rs @@ -120,7 +120,7 @@ mod tests { let tx = TransactionRequest { nonce: Some(0), value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()), gas_price: Some(20e9 as u128), gas: Some(21000), ..Default::default() diff --git a/crates/provider/src/provider.rs b/crates/provider/src/provider.rs index 62d7e747706..6edc1ff9620 100644 --- a/crates/provider/src/provider.rs +++ b/crates/provider/src/provider.rs @@ -1103,7 +1103,7 @@ impl Provider for RootProvider { #[allow(clippy::missing_const_for_fn)] mod tests { use super::*; - use alloy_primitives::{address, b256, bytes}; + use alloy_primitives::{address, b256, bytes, TxKind}; use alloy_rpc_types::request::TransactionRequest; extern crate self as alloy_provider; @@ -1227,7 +1227,7 @@ mod tests { let tx = TransactionRequest { value: Some(U256::from(100)), - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Some(TxKind::Call(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"))), gas_price: Some(20e9 as u128), gas: Some(21000), ..Default::default() diff --git a/crates/rpc-types/src/eth/block.rs b/crates/rpc-types/src/eth/block.rs index 904b1e0d694..788c236640a 100644 --- a/crates/rpc-types/src/eth/block.rs +++ b/crates/rpc-types/src/eth/block.rs @@ -1,5 +1,7 @@ //! Block RPC types. +#![allow(unknown_lints, non_local_definitions)] + use crate::{other::OtherFields, Transaction, Withdrawal}; pub use alloy_eips::{ calc_blob_gasprice, calc_excess_blob_gas, BlockId, BlockNumberOrTag, RpcBlockHash, diff --git a/crates/rpc-types/src/eth/transaction/mod.rs b/crates/rpc-types/src/eth/transaction/mod.rs index a8a6460b202..94ac19e4c57 100644 --- a/crates/rpc-types/src/eth/transaction/mod.rs +++ b/crates/rpc-types/src/eth/transaction/mod.rs @@ -5,7 +5,7 @@ use alloy_consensus::{ SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxEnvelope, TxLegacy, TxType, }; -use alloy_primitives::{Address, Bytes, B256, U256}; +use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; use serde::{Deserialize, Serialize}; pub use alloy_consensus::BlobTransactionSidecar; @@ -153,9 +153,11 @@ impl Transaction { (None, None) => None, }; + let to = self.to.map(TxKind::Call); + TransactionRequest { from: Some(self.from), - to: self.to, + to, gas: Some(self.gas), gas_price, value: Some(self.value), diff --git a/crates/rpc-types/src/eth/transaction/request.rs b/crates/rpc-types/src/eth/transaction/request.rs index 58d72b68ae7..d04050e43e1 100644 --- a/crates/rpc-types/src/eth/transaction/request.rs +++ b/crates/rpc-types/src/eth/transaction/request.rs @@ -16,7 +16,7 @@ pub struct TransactionRequest { /// The address of the transaction author. pub from: Option
, /// The destination address of the transaction. - pub to: Option
, + pub to: Option, /// The legacy gas price. #[serde( default, @@ -136,7 +136,7 @@ impl TransactionRequest { /// Sets the recipient address for the transaction. #[inline] pub const fn to(mut self, to: Address) -> Self { - self.to = Some(to); + self.to = Some(TxKind::Call(to)); self } @@ -211,12 +211,14 @@ impl TransactionRequest { /// If required fields are missing. Use `complete_legacy` to check if the /// request can be built. fn build_legacy(self) -> TxLegacy { + let checked_to = self.to.expect("checked in complete_legacy."); + TxLegacy { chain_id: self.chain_id, nonce: self.nonce.expect("checked in complete_legacy"), gas_price: self.gas_price.expect("checked in complete_legacy"), gas_limit: self.gas.expect("checked in complete_legacy"), - to: self.to.into(), + to: checked_to, value: self.value.unwrap_or_default(), input: self.input.into_input().unwrap_or_default(), } @@ -229,6 +231,8 @@ impl TransactionRequest { /// If required fields are missing. Use `complete_1559` to check if the /// request can be built. fn build_1559(self) -> TxEip1559 { + let checked_to = self.to.expect("checked in complete_1559."); + TxEip1559 { chain_id: self.chain_id.unwrap_or(1), nonce: self.nonce.expect("checked in invalid_common_fields"), @@ -237,7 +241,7 @@ impl TransactionRequest { .expect("checked in invalid_1559_fields"), max_fee_per_gas: self.max_fee_per_gas.expect("checked in invalid_1559_fields"), gas_limit: self.gas.expect("checked in invalid_common_fields"), - to: self.to.into(), + to: checked_to, value: self.value.unwrap_or_default(), input: self.input.into_input().unwrap_or_default(), access_list: self.access_list.unwrap_or_default(), @@ -251,12 +255,14 @@ impl TransactionRequest { /// If required fields are missing. Use `complete_2930` to check if the /// request can be built. fn build_2930(self) -> TxEip2930 { + let checked_to = self.to.expect("checked in complete_2930."); + TxEip2930 { chain_id: self.chain_id.unwrap_or(1), nonce: self.nonce.expect("checked in complete_2930"), gas_price: self.gas_price.expect("checked in complete_2930"), gas_limit: self.gas.expect("checked in complete_2930"), - to: self.to.into(), + to: checked_to, value: self.value.unwrap_or_default(), input: self.input.into_input().unwrap_or_default(), access_list: self.access_list.unwrap_or_default(), @@ -272,6 +278,12 @@ impl TransactionRequest { fn build_4844(mut self) -> TxEip4844WithSidecar { self.populate_blob_hashes(); + let checked_to = self.to.expect("checked in complete_4844."); + let to_address = match checked_to { + TxKind::Create => panic!("the field `to` can only be of type TxKind::Call(Account). Please change it accordingly."), + TxKind::Call(to) => to, + }; + TxEip4844WithSidecar { sidecar: self.sidecar.expect("checked in complete_4844"), tx: TxEip4844 { @@ -282,7 +294,7 @@ impl TransactionRequest { max_priority_fee_per_gas: self .max_priority_fee_per_gas .expect("checked in complete_4844"), - to: self.to.expect("checked in complete_4844"), + to: to_address, value: self.value.unwrap_or_default(), access_list: self.access_list.unwrap_or_default(), blob_versioned_hashes: self @@ -302,6 +314,9 @@ impl TransactionRequest { if self.gas.is_none() { missing.push("gas_limit"); } + if self.to.is_none() { + missing.push("to"); + } missing } @@ -582,7 +597,7 @@ impl From for TransactionRequest { fn from(tx: TxLegacy) -> TransactionRequest { TransactionRequest { from: None, - to: if let TxKind::Call(to) = tx.to { Some(to) } else { None }, + to: if let TxKind::Call(to) = tx.to { Some(TxKind::Call(to)) } else { None }, gas_price: Some(tx.gas_price), gas: Some(tx.gas_limit), value: Some(tx.value), @@ -599,7 +614,7 @@ impl From for TransactionRequest { fn from(tx: TxEip2930) -> TransactionRequest { TransactionRequest { from: None, - to: if let TxKind::Call(to) = tx.to { Some(to) } else { None }, + to: if let TxKind::Call(to) = tx.to { Some(TxKind::Call(to)) } else { None }, gas_price: Some(tx.gas_price), gas: Some(tx.gas_limit), value: Some(tx.value), @@ -617,7 +632,7 @@ impl From for TransactionRequest { fn from(tx: TxEip1559) -> TransactionRequest { TransactionRequest { from: None, - to: if let TxKind::Call(to) = tx.to { Some(to) } else { None }, + to: if let TxKind::Call(to) = tx.to { Some(TxKind::Call(to)) } else { None }, max_fee_per_gas: Some(tx.max_fee_per_gas), max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas), gas: Some(tx.gas_limit), @@ -636,7 +651,7 @@ impl From for TransactionRequest { fn from(tx: TxEip4844) -> TransactionRequest { TransactionRequest { from: None, - to: Some(tx.to), + to: Some(TxKind::Call(tx.to)), max_fee_per_blob_gas: Some(tx.max_fee_per_blob_gas), gas: Some(tx.gas_limit), max_fee_per_gas: Some(tx.max_fee_per_gas), @@ -659,7 +674,7 @@ impl From for TransactionRequest { let tx = tx.tx; TransactionRequest { from: None, - to: Some(tx.to), + to: Some(TxKind::Call(tx.to)), max_fee_per_blob_gas: Some(tx.max_fee_per_blob_gas), gas: Some(tx.gas_limit), max_fee_per_gas: Some(tx.max_fee_per_gas),