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

Commit

Permalink
FIX: Accept 'input' or 'data' or both in transaction request (#460)
Browse files Browse the repository at this point in the history
* FIX: Accept 'input' or 'data' or both in transaction request

* FIX: Add TransactionRequestCompat

* FIX: Remove duplication
  • Loading branch information
aakoshh authored Dec 8, 2023
1 parent 0b885c0 commit 1841a4f
Showing 1 changed file with 71 additions and 12 deletions.
83 changes: 71 additions & 12 deletions fendermint/eth/api/src/apis/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,39 +1057,73 @@ pub async fn unsubscribe<C>(
uninstall_filter(data, Params((filter_id,))).await
}

use params::{EstimateGasParams, SubscribeParams};

use self::params::TypedTransactionCompat;
use params::{EstimateGasParams, SubscribeParams, TypedTransactionCompat};

mod params {
use ethers_core::types::transaction::eip2718::TypedTransaction;
use ethers_core::types::Eip1559TransactionRequest;
use ethers_core::types::{self as et, Eip2930TransactionRequest, TransactionRequest};
use serde::{Deserialize, Serialize};
use serde::Deserialize;

use crate::state::WebSocketId;

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
/// Copied from `ethers` to override `data` deserialization.
///
/// See <https://github.com/filecoin-project/lotus/pull/11471>
///
/// This is accepted for gas estimation only.
#[derive(Clone, Default, Deserialize, PartialEq, Eq, Debug)]
pub struct TransactionRequestCompat {
#[serde(flatten)]
orig: TransactionRequest,
input: Option<et::Bytes>,
}

impl From<TransactionRequestCompat> for TransactionRequest {
fn from(value: TransactionRequestCompat) -> Self {
let mut request = value.orig;
request.data = value.input.or(request.data);
request
}
}

/// Copied from `ethers` to override `data` deserialization.
///
/// See <https://github.com/filecoin-project/lotus/pull/11471>
#[derive(Clone, Default, Deserialize, PartialEq, Eq, Debug)]
pub struct Eip1559TransactionRequestCompat {
#[serde(flatten)]
orig: Eip1559TransactionRequest,
input: Option<et::Bytes>,
}

impl From<Eip1559TransactionRequestCompat> for Eip1559TransactionRequest {
fn from(value: Eip1559TransactionRequestCompat) -> Self {
let mut request = value.orig;
request.data = value.input.or(request.data);
request
}
}

#[derive(Deserialize, Clone, PartialEq, Eq, Debug)]
// NOTE: Using untagged so is able to deserialize as a legacy transaction
// directly if the type is not set. Needed for backward compatibility.
// #[serde(tag = "type")]
#[serde(untagged)]
pub enum TypedTransactionCompat {
// 0x00
#[serde(rename = "0x00", alias = "0x0")]
Legacy(TransactionRequest),
Legacy(TransactionRequestCompat),
#[serde(rename = "0x02", alias = "0x2")]
Eip1559(Eip1559TransactionRequest),
// 0x01
Eip1559(Eip1559TransactionRequestCompat),
#[serde(rename = "0x01", alias = "0x1")]
Eip2930(Eip2930TransactionRequest),
}

impl From<TypedTransactionCompat> for TypedTransaction {
fn from(value: TypedTransactionCompat) -> Self {
match value {
TypedTransactionCompat::Eip1559(v) => TypedTransaction::Eip1559(v),
TypedTransactionCompat::Legacy(v) => TypedTransaction::Legacy(v),
TypedTransactionCompat::Eip1559(v) => TypedTransaction::Eip1559(v.into()),
TypedTransactionCompat::Legacy(v) => TypedTransaction::Legacy(v.into()),
TypedTransactionCompat::Eip2930(v) => TypedTransaction::Eip2930(v),
}
}
Expand Down Expand Up @@ -1117,7 +1151,9 @@ mod params {

#[cfg(test)]
mod tests {
use crate::apis::eth::params::EstimateGasParams;
use ethers_core::types::Eip1559TransactionRequest;

use crate::apis::eth::params::{Eip1559TransactionRequestCompat, EstimateGasParams};

#[test]
fn deserialize_estimate_gas_params() {
Expand All @@ -1127,5 +1163,28 @@ mod params {
let r = serde_json::from_str::<EstimateGasParams>(raw_str);
assert!(r.is_ok());
}

#[test]
fn deserialize_input_and_data() {
let examples = [
("01", r#" "data":"0x0d", "input": "0x01" "#),
("02", r#" "data":"0x02" "#),
("03", r#" "input":"0x03" "#),
];
for (exp, frag) in examples {
let json = format!(
"{{ {frag}, \"from\":\"0x1a79385ead0e873fe0c441c034636d3edf7014cc\",\"maxFeePerGas\":\"0x596836d0\",\"maxPriorityFeePerGas\":\"0x59682f00\" }}"
);

let r: Eip1559TransactionRequest =
serde_json::from_str::<Eip1559TransactionRequestCompat>(&json)
.unwrap_or_else(|e| panic!("failed to parse {json}: {e}"))
.into();

let d = r.data.expect("data is empty");

assert_eq!(hex::encode(d), exp)
}
}
}
}

0 comments on commit 1841a4f

Please sign in to comment.