use crate::SpanBatchError;
use alloc::vec::Vec;
use alloy_consensus::{SignableTransaction, Signed, TxEip7702};
use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization};
use alloy_primitives::{Address, Signature, U256};
use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable};
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
pub struct SpanBatchEip7702TransactionData {
pub value: U256,
pub max_priority_fee_per_gas: U256,
pub max_fee_per_gas: U256,
pub data: Bytes,
pub access_list: AccessList,
pub authorization_list: Vec<SignedAuthorization>,
}
impl SpanBatchEip7702TransactionData {
pub fn to_signed_tx(
&self,
nonce: u64,
gas: u64,
to: Address,
chain_id: u64,
signature: Signature,
) -> Result<Signed<TxEip7702>, SpanBatchError> {
let mut max_fee_per_gas = [0u8; 16];
max_fee_per_gas.copy_from_slice(&self.max_fee_per_gas.to_be_bytes::<32>()[16..]);
let max_fee_per_gas = u128::from_be_bytes(max_fee_per_gas);
let mut max_priority_fee_per_gas = [0u8; 16];
max_priority_fee_per_gas
.copy_from_slice(&self.max_priority_fee_per_gas.to_be_bytes::<32>()[16..]);
let max_priority_fee_per_gas = u128::from_be_bytes(max_priority_fee_per_gas);
let eip7702_tx = TxEip7702 {
chain_id,
nonce,
max_fee_per_gas,
max_priority_fee_per_gas,
gas_limit: gas,
to,
value: self.value,
input: self.data.clone().into(),
access_list: self.access_list.clone(),
authorization_list: self.authorization_list.clone(),
};
let signature_hash = eip7702_tx.signature_hash();
Ok(Signed::new_unchecked(eip7702_tx, signature, signature_hash))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::SpanBatchTransactionData;
use alloc::{vec, vec::Vec};
use alloy_rlp::{Decodable, Encodable};
use alloy_rpc_types_eth::Authorization;
#[test]
fn test_eip7702_to_signed_tx() {
let authorization = Authorization {
chain_id: U256::from(0x01),
address: Address::left_padding_from(&[0x01, 0x02, 0x03]),
nonce: 2,
};
let signature = Signature::test_signature();
let arb_authorization: SignedAuthorization = authorization.into_signed(signature);
let variable_fee_tx = SpanBatchEip7702TransactionData {
value: U256::from(0xFF),
max_fee_per_gas: U256::from(0xEE),
max_priority_fee_per_gas: U256::from(0xDD),
data: Bytes::from(alloc::vec![0x01, 0x02, 0x03]),
access_list: AccessList::default(),
authorization_list: vec![arb_authorization],
};
let signed_tx = variable_fee_tx
.to_signed_tx(0, 0, Address::ZERO, 0, Signature::test_signature())
.unwrap();
assert_eq!(*signed_tx.signature(), Signature::test_signature());
}
#[test]
fn encode_eip7702_tx_data_roundtrip() {
let authorization = Authorization {
chain_id: U256::from(0x01),
address: Address::left_padding_from(&[0x01, 0x02, 0x03]),
nonce: 2,
};
let signature = Signature::test_signature();
let arb_authorization: SignedAuthorization = authorization.into_signed(signature);
let variable_fee_tx = SpanBatchEip7702TransactionData {
value: U256::from(0xFF),
max_fee_per_gas: U256::from(0xEE),
max_priority_fee_per_gas: U256::from(0xDD),
data: Bytes::from(alloc::vec![0x01, 0x02, 0x03]),
access_list: AccessList::default(),
authorization_list: vec![arb_authorization],
};
let mut encoded_buf = Vec::new();
SpanBatchTransactionData::Eip7702(variable_fee_tx.clone()).encode(&mut encoded_buf);
let decoded = SpanBatchTransactionData::decode(&mut encoded_buf.as_slice()).unwrap();
let SpanBatchTransactionData::Eip7702(variable_fee_decoded) = decoded else {
panic!("Expected SpanBatchEip7702TransactionData, got {:?}", decoded);
};
assert_eq!(variable_fee_tx, variable_fee_decoded);
}
}