use bytes::Bytes;
use ethrex_common::{
Address, H160, H256, U256,
types::{PrivilegedL2Transaction, TxType},
};
use ethrex_rpc::{
EthClient,
clients::{EthClientError, Overrides},
types::receipt::RpcLogInfo,
};
use crate::build_generic_tx;
pub struct PrivilegedTransactionData {
pub value: U256,
pub to_address: H160,
pub transaction_id: U256,
pub from: H160,
pub gas_limit: U256,
pub calldata: Vec<u8>,
}
impl PrivilegedTransactionData {
pub fn from_log(log: RpcLogInfo) -> Result<PrivilegedTransactionData, String> {
let from = H256::from_slice(log.data.get(0..32).ok_or(
"Failed to parse gas_limit from log: log.data[0..32] out of bounds".to_owned(),
)?);
let from_address = hash_to_address(from);
let to = H256::from_slice(log.data.get(32..64).ok_or(
"Failed to parse gas_limit from log: log.data[32..64] out of bounds".to_owned(),
)?);
let to_address = hash_to_address(to);
let transaction_id = U256::from_big_endian(log.data.get(64..96).ok_or(
"Failed to parse gas_limit from log: log.data[64..96] out of bounds".to_owned(),
)?);
let value = U256::from_big_endian(log.data.get(96..128).ok_or(
"Failed to parse gas_limit from log: log.data[96..128] out of bounds".to_owned(),
)?);
let gas_limit = U256::from_big_endian(log.data.get(128..160).ok_or(
"Failed to parse gas_limit from log: log.data[128..160] out of bounds".to_owned(),
)?);
let calldata_len = U256::from_big_endian(log.data.get(192..224).ok_or(
"Failed to parse calldata_len from log: log.data[192..224] out of bounds".to_owned(),
)?);
let calldata_len = usize::try_from(calldata_len).map_err(|_| {
"Failed to parse calldata_len from log: value overflows usize".to_owned()
})?;
let calldata = log.data.get(224..224 + calldata_len).ok_or(
"Failed to parse calldata from log: log.data[224..224 + calldata_len] out of bounds"
.to_owned(),
)?;
Ok(Self {
value,
to_address,
transaction_id,
from: from_address,
gas_limit,
calldata: calldata.to_vec(),
})
}
pub async fn into_tx(
&self,
eth_client: &EthClient,
chain_id: u64,
gas_price: u64,
) -> Result<PrivilegedL2Transaction, EthClientError> {
let generic_tx =
build_generic_tx(
eth_client,
TxType::Privileged,
self.to_address,
self.from,
Bytes::copy_from_slice(&self.calldata),
Overrides {
chain_id: Some(chain_id),
nonce: Some(u64::try_from(self.transaction_id).map_err(|_| {
EthClientError::Custom("transaction_id overflows u64".to_owned())
})?),
value: Some(self.value),
gas_limit: Some(u64::try_from(self.gas_limit).map_err(|_| {
EthClientError::Custom("gas_limit overflows u64".to_owned())
})?),
max_fee_per_gas: Some(gas_price),
max_priority_fee_per_gas: Some(gas_price),
..Default::default()
},
)
.await?;
Ok(generic_tx.try_into()?)
}
}
pub fn hash_to_address(hash: H256) -> Address {
Address::from_slice(&hash.as_fixed_bytes()[12..])
}