use std::cell::RefCell;
use alloy_primitives::{Address, Bytes, U256};
use clap::Args;
use mega_evm::{
alloy_evm::{IntoTxEnv, RecoveredTx},
MegaTransaction,
};
use super::{load_hex, parse_ether_value, Result};
thread_local! {
static INPUT_OVERRIDE: RefCell<Option<Bytes>> = const { RefCell::new(None) };
}
#[derive(Args, Debug, Clone, Default)]
#[command(next_help_heading = "Transaction Override Options")]
pub struct TxOverrideArgs {
#[arg(long = "override.gas-limit", visible_aliases = ["override.gaslimit"], value_name = "GAS")]
pub gas_limit: Option<u64>,
#[arg(long = "override.value", value_name = "VALUE")]
pub value: Option<String>,
#[arg(long = "override.input", visible_aliases = ["override.data"], value_name = "HEX")]
pub input: Option<String>,
#[arg(long = "override.input-file", visible_aliases = ["override.data-file"], value_name = "FILE")]
pub input_file: Option<String>,
}
impl TxOverrideArgs {
pub fn has_overrides(&self) -> bool {
self.gas_limit.is_some() ||
self.value.is_some() ||
self.input.is_some() ||
self.input_file.is_some()
}
pub fn wrap<T: Copy>(&self, tx: T) -> Result<OverriddenTx<T>> {
let has_input_override =
if let Some(bytes) = load_hex(self.input.clone(), self.input_file.clone())? {
INPUT_OVERRIDE.with(|cell| cell.borrow_mut().replace(bytes));
true
} else {
INPUT_OVERRIDE.with(|cell| cell.borrow_mut().take());
false
};
Ok(OverriddenTx {
inner: tx,
overrides: TxOverrides {
gas_limit: self.gas_limit,
value: self.value.as_deref().map(parse_ether_value).transpose()?,
has_input_override,
},
})
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct TxOverrides {
pub gas_limit: Option<u64>,
pub value: Option<U256>,
pub has_input_override: bool,
}
impl TxOverrides {
pub fn apply(&self, tx: &mut MegaTransaction) {
if let Some(gas_limit) = self.gas_limit {
tx.base.gas_limit = gas_limit;
}
if let Some(value) = self.value {
tx.base.value = value;
}
if self.has_input_override {
if let Some(input) = INPUT_OVERRIDE.with(|cell| cell.borrow().clone()) {
tx.base.data = input;
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct OverriddenTx<T: Copy> {
inner: T,
overrides: TxOverrides,
}
impl<T: Copy> OverriddenTx<T> {
pub fn inner(&self) -> &T {
&self.inner
}
}
impl<T: IntoTxEnv<MegaTransaction> + Copy> IntoTxEnv<MegaTransaction> for OverriddenTx<T> {
fn into_tx_env(self) -> MegaTransaction {
let mut tx = self.inner.into_tx_env();
self.overrides.apply(&mut tx);
tx
}
}
impl<Tx, T: RecoveredTx<Tx> + Copy> RecoveredTx<Tx> for OverriddenTx<T> {
fn tx(&self) -> &Tx {
self.inner.tx()
}
fn signer(&self) -> &Address {
self.inner.signer()
}
}