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

FIX: Accept 'input' or 'data' or both in transaction request #460

Merged
merged 3 commits into from
Dec 8, 2023
Merged
Changes from all commits
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
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)
}
}
}
}