1use super::SeismicNodeCore;
2use crate::SeismicEthApi;
3use alloy_consensus::transaction::Either;
4use alloy_eips::eip7702::{RecoveredAuthorization, SignedAuthorization};
5use alloy_primitives::{TxKind, U256};
6use alloy_rpc_types_eth::transaction::TransactionRequest;
7use reth_evm::{execute::BlockExecutorFactory, ConfigureEvm, EvmEnv, EvmFactory, SpecFor};
8use reth_node_api::NodePrimitives;
9use reth_rpc_eth_api::{
10 helpers::{estimate::EstimateCall, Call, EthCall, LoadBlock, LoadState, SpawnBlocking},
11 FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError,
12};
13use reth_rpc_eth_types::{revm_utils::CallFees, EthApiError, RpcInvalidTransactionError};
14use reth_storage_api::{ProviderHeader, ProviderTx};
15use revm::{context::TxEnv, context_interface::Block, Database};
16use seismic_alloy_consensus::SeismicTxType;
17use seismic_revm::{transaction::abstraction::RngMode, SeismicTransaction};
18use tracing::debug;
19
20impl<N> EthCall for SeismicEthApi<N>
21where
22 Self: EstimateCall + LoadBlock + FullEthApiTypes,
23 N: SeismicNodeCore,
24{
25}
26
27impl<N> EstimateCall for SeismicEthApi<N>
28where
29 Self: Call,
30 Self::Error: From<EthApiError>,
31 N: SeismicNodeCore,
32{
33}
34
35impl<N> Call for SeismicEthApi<N>
36where
37 Self: LoadState<
38 Evm: ConfigureEvm<
39 Primitives: NodePrimitives<
40 BlockHeader = ProviderHeader<Self::Provider>,
41 SignedTx = ProviderTx<Self::Provider>,
42 >,
43 BlockExecutorFactory: BlockExecutorFactory<
44 EvmFactory: EvmFactory<Tx = seismic_revm::SeismicTransaction<TxEnv>>,
45 >,
46 >,
47 Error: FromEvmError<Self::Evm>,
48 > + SpawnBlocking,
49 Self::Error: From<EthApiError>,
50 N: SeismicNodeCore,
51{
52 #[inline]
53 fn call_gas_limit(&self) -> u64 {
54 self.inner.gas_cap()
55 }
56
57 #[inline]
58 fn max_simulate_blocks(&self) -> u64 {
59 self.inner.max_simulate_blocks()
60 }
61
62 fn create_txn_env(
63 &self,
64 evm_env: &EvmEnv<SpecFor<Self::Evm>>,
65 request: TransactionRequest,
66 mut db: impl Database<Error: Into<EthApiError>>,
67 ) -> Result<SeismicTransaction<TxEnv>, Self::Error> {
68 if request.blob_versioned_hashes.as_ref().is_some_and(|hashes| hashes.is_empty()) {
70 return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into_eth_err())
71 }
72
73 let tx_type = if request.authorization_list.is_some() {
74 SeismicTxType::Eip7702
75 } else if request.max_fee_per_gas.is_some() || request.max_priority_fee_per_gas.is_some() {
76 SeismicTxType::Eip1559
77 } else if request.access_list.is_some() {
78 SeismicTxType::Eip2930
79 } else {
80 SeismicTxType::Seismic
81 } as u8;
82
83 let TransactionRequest {
84 from,
85 to,
86 gas_price,
87 max_fee_per_gas,
88 max_priority_fee_per_gas,
89 gas,
90 value,
91 input,
92 nonce,
93 access_list,
94 chain_id,
95 blob_versioned_hashes,
96 max_fee_per_blob_gas,
97 authorization_list,
98 transaction_type: _,
99 sidecar: _,
100 } = request;
101
102 let CallFees { max_priority_fee_per_gas, gas_price, max_fee_per_blob_gas } =
103 CallFees::ensure_fees(
104 gas_price.map(U256::from),
105 max_fee_per_gas.map(U256::from),
106 max_priority_fee_per_gas.map(U256::from),
107 U256::from(evm_env.block_env.basefee),
108 blob_versioned_hashes.as_deref(),
109 max_fee_per_blob_gas.map(U256::from),
110 evm_env.block_env.blob_gasprice().map(U256::from),
111 )?;
112
113 let gas_limit = gas.unwrap_or(
114 evm_env.block_env.gas_limit,
120 );
121
122 let chain_id = chain_id.unwrap_or(evm_env.cfg_env.chain_id);
123
124 let caller = from.unwrap_or_default();
125
126 let nonce = if let Some(nonce) = nonce {
127 nonce
128 } else {
129 db.basic(caller).map_err(Into::into)?.map(|acc| acc.nonce).unwrap_or_default()
130 };
131
132 let authorization_list: Vec<Either<SignedAuthorization, RecoveredAuthorization>> =
133 authorization_list
134 .unwrap_or_default()
135 .iter()
136 .map(|auth| Either::Left(auth.clone()))
137 .collect();
138 let env = TxEnv {
139 tx_type,
140 gas_limit,
141 nonce,
142 caller,
143 gas_price: gas_price.saturating_to(),
144 gas_priority_fee: max_priority_fee_per_gas.map(|v| v.saturating_to()),
145 kind: to.unwrap_or(TxKind::Create),
146 value: value.unwrap_or_default(),
147 data: input
148 .try_into_unique_input()
149 .map_err(Self::Error::from_eth_err)?
150 .unwrap_or_default(),
151 chain_id: Some(chain_id),
152 access_list: access_list.unwrap_or_default(),
153 blob_hashes: blob_versioned_hashes.unwrap_or_default(),
155 max_fee_per_blob_gas: max_fee_per_blob_gas
156 .map(|v| v.saturating_to())
157 .unwrap_or_default(),
158 authorization_list,
160 };
161
162 debug!("reth-seismic-rpc::eth create_txn_env {:?}", env);
163
164 Ok(SeismicTransaction {
165 base: env,
166 tx_hash: Default::default(),
167 rng_mode: RngMode::Simulation,
168 })
169 }
170}