mega_evme/common/
tx_override.rs1use std::cell::RefCell;
7
8use alloy_eips::{Encodable2718, Typed2718};
9use alloy_primitives::{Address, Bytes, TxHash, U256};
10use clap::Args;
11use mega_evm::{
12 alloy_evm::{IntoTxEnv, RecoveredTx},
13 MegaTransaction, MegaTransactionExt,
14};
15
16use super::{load_hex, parse_ether_value, Result};
17
18thread_local! {
20 static INPUT_OVERRIDE: RefCell<Option<Bytes>> = const { RefCell::new(None) };
21}
22
23#[derive(Args, Debug, Clone, Default)]
25#[command(next_help_heading = "Transaction Override Options")]
26pub struct TxOverrideArgs {
27 #[arg(long = "override.gas-limit", visible_aliases = ["override.gaslimit"], value_name = "GAS")]
29 pub gas_limit: Option<u64>,
30
31 #[arg(long = "override.value", value_name = "VALUE")]
35 pub value: Option<String>,
36
37 #[arg(long = "override.input", visible_aliases = ["override.data"], value_name = "HEX")]
39 pub input: Option<String>,
40
41 #[arg(long = "override.input-file", visible_aliases = ["override.data-file"], value_name = "FILE")]
43 pub input_file: Option<String>,
44}
45
46impl TxOverrideArgs {
47 pub fn has_overrides(&self) -> bool {
49 self.gas_limit.is_some() ||
50 self.value.is_some() ||
51 self.input.is_some() ||
52 self.input_file.is_some()
53 }
54
55 pub fn wrap<T: Copy>(&self, tx: T) -> Result<OverriddenTx<T>> {
57 let has_input_override =
59 if let Some(bytes) = load_hex(self.input.clone(), self.input_file.clone())? {
60 INPUT_OVERRIDE.with(|cell| cell.borrow_mut().replace(bytes));
61 true
62 } else {
63 INPUT_OVERRIDE.with(|cell| cell.borrow_mut().take());
64 false
65 };
66
67 Ok(OverriddenTx {
68 inner: tx,
69 overrides: TxOverrides {
70 gas_limit: self.gas_limit,
71 value: self.value.as_deref().map(parse_ether_value).transpose()?,
72 has_input_override,
73 },
74 })
75 }
76}
77
78#[derive(Debug, Clone, Copy, Default)]
84pub struct TxOverrides {
85 pub gas_limit: Option<u64>,
87 pub value: Option<U256>,
89 pub has_input_override: bool,
91}
92
93impl TxOverrides {
94 pub fn apply(&self, tx: &mut MegaTransaction) {
96 if let Some(gas_limit) = self.gas_limit {
97 tx.base.gas_limit = gas_limit;
98 }
99 if let Some(value) = self.value {
100 tx.base.value = value;
101 }
102 if self.has_input_override {
103 if let Some(input) = INPUT_OVERRIDE.with(|cell| cell.borrow().clone()) {
104 tx.base.data = input;
105 }
106 }
107 }
108}
109
110#[derive(Debug, Clone, Copy)]
115pub struct OverriddenTx<T: Copy> {
116 inner: T,
117 overrides: TxOverrides,
118}
119
120impl<T: Copy> OverriddenTx<T> {
121 pub fn inner(&self) -> &T {
123 &self.inner
124 }
125}
126
127impl<T: IntoTxEnv<MegaTransaction> + Copy> IntoTxEnv<MegaTransaction> for OverriddenTx<T> {
129 fn into_tx_env(self) -> MegaTransaction {
130 let mut tx = self.inner.into_tx_env();
131 self.overrides.apply(&mut tx);
132 tx
133 }
134}
135
136impl<Tx, T: RecoveredTx<Tx> + Copy> RecoveredTx<Tx> for OverriddenTx<T> {
138 fn tx(&self) -> &Tx {
139 self.inner.tx()
140 }
141
142 fn signer(&self) -> &Address {
143 self.inner.signer()
144 }
145}
146
147impl<T: Typed2718 + Copy> Typed2718 for OverriddenTx<T> {
149 fn ty(&self) -> u8 {
150 self.inner.ty()
151 }
152}
153
154impl<T: Encodable2718 + Copy> Encodable2718 for OverriddenTx<T> {
158 fn type_flag(&self) -> Option<u8> {
159 self.inner.type_flag()
160 }
161
162 fn encode_2718_len(&self) -> usize {
163 self.inner.encode_2718_len()
164 }
165
166 fn encode_2718(&self, out: &mut dyn alloy_primitives::bytes::BufMut) {
167 self.inner.encode_2718(out)
168 }
169}
170
171impl<T: MegaTransactionExt + Copy> MegaTransactionExt for OverriddenTx<T> {
175 fn tx_hash(&self) -> TxHash {
176 self.inner.tx_hash()
177 }
178}