Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

feat(core): add helpers to unwrap TypedTransaction #1278

Merged
merged 5 commits into from
May 17, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions ethers-core/src/types/transaction/eip2718.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ pub enum TypedTransactionError {
/// Missing transaction payload when decoding from RLP
#[error("Missing transaction payload when decoding")]
MissingTransactionPayload,
/// Wrong transaction type requested
#[error("Wrong transaction type requested")]
WrongTransactionType,
}

#[cfg(feature = "legacy")]
Expand Down Expand Up @@ -398,6 +401,143 @@ impl From<&Transaction> for TypedTransaction {
}
}

impl TypedTransaction {
#[allow(dead_code)]
fn as_legacy_ref(&self) -> Result<&TransactionRequest, TypedTransactionError> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are all private, and marked as dead?

I think they should rather return a simple Option<>

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree

match self {
Legacy(tx) => Ok(tx),
_ => Err(TypedTransactionError::WrongTransactionType),
}
}
#[allow(dead_code)]
fn as_eip2930_ref(&self) -> Result<&Eip2930TransactionRequest, TypedTransactionError> {
match self {
Eip2930(tx) => Ok(tx),
_ => Err(TypedTransactionError::WrongTransactionType),
}
}
#[allow(dead_code)]
fn as_eip1559_ref(&self) -> Result<&Eip1559TransactionRequest, TypedTransactionError> {
match self {
Eip1559(tx) => Ok(tx),
_ => Err(TypedTransactionError::WrongTransactionType),
}
}
}

impl TypedTransaction {
fn as_eip1559(&self) -> Eip1559TransactionRequest {
match self {
Eip1559(tx) => tx.clone(),
_ => Eip1559TransactionRequest {
from: self.from().copied(),
to: self.to().cloned(),
nonce: self.nonce().copied(),
value: self.value().copied(),
gas: self.gas().copied(),
chain_id: self.chain_id(),
data: self.data().cloned(),
access_list: self.access_list().cloned().unwrap_or_default(),
..Default::default()
},
}
}
fn into_eip1559(self) -> Eip1559TransactionRequest {
match self {
Eip1559(tx) => tx,
_ => (&self).as_eip1559(),
}
}
}

impl From<&TypedTransaction> for Eip1559TransactionRequest {
fn from(src: &TypedTransaction) -> Eip1559TransactionRequest {
src.as_eip1559()
}
}

impl From<TypedTransaction> for Eip1559TransactionRequest {
fn from(src: TypedTransaction) -> Eip1559TransactionRequest {
src.into_eip1559()
}
}

impl TypedTransaction {
fn as_legacy(&self) -> TransactionRequest {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we basically clone every field, I think we should take ownership here so the caller can decide if a clone is necessary, otherwise, converting always requires a clone

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah seems like we should not have as_* methods then, let's remove them and replace with into_*

match self {
Legacy(tx) => tx.clone(),
_ => TransactionRequest {
from: self.from().copied(),
to: self.to().cloned(),
nonce: self.nonce().copied(),
value: self.value().copied(),
gas: self.gas().copied(),
gas_price: self.gas_price(),
chain_id: self.chain_id(),
data: self.data().cloned(),
#[cfg(feature = "celo")]
#[cfg_attr(docsrs, doc(cfg(feature = "celo")))]
fee_currency: None,
#[cfg(feature = "celo")]
#[cfg_attr(docsrs, doc(cfg(feature = "celo")))]
gateway_fee_recipient: None,
#[cfg(feature = "celo")]
#[cfg_attr(docsrs, doc(cfg(feature = "celo")))]
gateway_fee: None,
},
}
}
fn into_legacy(self) -> TransactionRequest {
match self {
Legacy(tx) => tx,
_ => (&self).as_legacy(),
}
}
}

impl From<&TypedTransaction> for TransactionRequest {
fn from(src: &TypedTransaction) -> TransactionRequest {
src.as_legacy()
}
}

impl From<TypedTransaction> for TransactionRequest {
fn from(src: TypedTransaction) -> TransactionRequest {
src.into_legacy()
}
}

impl TypedTransaction {
fn as_eip2930(&self) -> Eip2930TransactionRequest {
match self {
Eip2930(tx) => tx.clone(),
_ => Eip2930TransactionRequest {
tx: self.as_legacy(),
access_list: self.access_list().cloned().unwrap_or_default(),
},
}
}

fn into_eip2930(self) -> Eip2930TransactionRequest {
match self {
Eip2930(tx) => tx,
_ => (&self).as_eip2930(),
}
}
}

impl From<&TypedTransaction> for Eip2930TransactionRequest {
fn from(src: &TypedTransaction) -> Eip2930TransactionRequest {
src.as_eip2930()
}
}

impl From<TypedTransaction> for Eip2930TransactionRequest {
fn from(src: TypedTransaction) -> Eip2930TransactionRequest {
src.into_eip2930()
}
}

#[cfg(test)]
mod tests {
use hex::ToHex;
Expand Down Expand Up @@ -614,4 +754,47 @@ mod tests {
let addr = Address::from_str("0x216b32eCEbAe6aF164921D3943cd7A9634FcB199").unwrap();
assert_eq!(addr, tx.from.unwrap());
}

#[test]
fn test_tx_casts() {
// eip1559 tx
let typed_tx_hex = hex::decode("02f86b8205390284773594008477359400830186a09496216849c49358b10257cb55b28ea603c874b05e865af3107a4000825544f838f7940000000000000000000000000000000000000001e1a00100000000000000000000000000000000000000000000000000000000000000").unwrap();
let tx_rlp = rlp::Rlp::new(typed_tx_hex.as_slice());
let tx = TypedTransaction::decode(&tx_rlp).unwrap();

{
let typed_tx: TypedTransaction = tx.clone().into();

let tx0: TransactionRequest = typed_tx.clone().into();
assert!(typed_tx.as_legacy_ref().is_err());

let tx1 = typed_tx.as_legacy();
let tx2 = typed_tx.into_legacy();

assert_eq!(tx0, tx1);
assert_eq!(tx1, tx2);
}
{
let typed_tx: TypedTransaction = tx.clone().into();
let tx0: Eip1559TransactionRequest = typed_tx.clone().into();
assert_eq!(tx.as_eip1559_ref().unwrap(), &tx0);

let tx1 = typed_tx.as_eip1559();
let tx2 = typed_tx.into_eip1559();

assert_eq!(tx0, tx1);
assert_eq!(tx1, tx2);
}
{
let typed_tx: TypedTransaction = tx.clone().into();
let tx0: Eip2930TransactionRequest = typed_tx.clone().into();
assert!(typed_tx.as_eip2930_ref().is_err());

let tx1 = typed_tx.as_eip2930();
let tx2 = typed_tx.into_eip2930();

assert_eq!(tx0, tx1);
assert_eq!(tx1, tx2);
}
}
}