use alloy_primitives::{B256, U128, U64};
use alloy_serde::OtherFields;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[doc(alias = "OptimismTxFields")]
pub struct OptimismTransactionFields {
#[serde(rename = "sourceHash", skip_serializing_if = "Option::is_none")]
pub source_hash: Option<B256>,
#[serde(rename = "mint", skip_serializing_if = "Option::is_none")]
pub mint: Option<U128>,
#[serde(rename = "isSystemTx", skip_serializing_if = "Option::is_none")]
#[doc(alias = "is_system_transaction")]
pub is_system_tx: Option<bool>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[doc(alias = "OptimismTxReceiptFields")]
pub struct OptimismTransactionReceiptFields {
#[serde(skip_serializing_if = "Option::is_none")]
pub deposit_nonce: Option<U64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deposit_receipt_version: Option<U64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
pub l1_fee: Option<u128>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "l1_fee_scalar_serde")]
pub l1_fee_scalar: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
pub l1_gas_price: Option<u128>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
pub l1_gas_used: Option<u128>,
}
impl From<OptimismTransactionFields> for OtherFields {
fn from(value: OptimismTransactionFields) -> Self {
serde_json::to_value(value).unwrap().try_into().unwrap()
}
}
impl From<OptimismTransactionReceiptFields> for OtherFields {
fn from(value: OptimismTransactionReceiptFields) -> Self {
serde_json::to_value(value).unwrap().try_into().unwrap()
}
}
mod l1_fee_scalar_serde {
use serde::{de, Deserialize};
pub(super) fn serialize<S>(value: &Option<f64>, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if let Some(v) = value {
return s.serialize_str(&v.to_string());
}
s.serialize_none()
}
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: Option<String> = Option::deserialize(deserializer)?;
if let Some(s) = s {
return Ok(Some(s.parse::<f64>().map_err(de::Error::custom)?));
}
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{json, Value};
#[test]
fn serialize_empty_optimism_transaction_receipt_fields_struct() {
let op_fields = OptimismTransactionReceiptFields::default();
let json = serde_json::to_value(op_fields).unwrap();
assert_eq!(json, json!({}));
}
#[test]
fn serialize_l1_fee_scalar() {
let op_fields = OptimismTransactionReceiptFields {
l1_fee_scalar: Some(0.678),
..OptimismTransactionReceiptFields::default()
};
let json = serde_json::to_value(op_fields).unwrap();
assert_eq!(json["l1FeeScalar"], serde_json::Value::String("0.678".to_string()));
}
#[test]
fn deserialize_l1_fee_scalar() {
let json = json!({
"l1FeeScalar": "0.678"
});
let op_fields: OptimismTransactionReceiptFields = serde_json::from_value(json).unwrap();
assert_eq!(op_fields.l1_fee_scalar, Some(0.678f64));
let json = json!({
"l1FeeScalar": Value::Null
});
let op_fields: OptimismTransactionReceiptFields = serde_json::from_value(json).unwrap();
assert_eq!(op_fields.l1_fee_scalar, None);
let json = json!({});
let op_fields: OptimismTransactionReceiptFields = serde_json::from_value(json).unwrap();
assert_eq!(op_fields.l1_fee_scalar, None);
}
}