diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index e9a8c991ab34..1602609c1568 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -494,25 +494,7 @@ where async fn send_raw_transaction(&self, tx: Bytes) -> EthResult { #[cfg(feature = "optimism")] - if let Some(endpoint) = self.network().sequencer_endpoint() { - let body = serde_json::to_string(&serde_json::json!({ - "jsonrpc": "2.0", - "method": "eth_sendRawTransaction", - "params": [format!("0x{}", hex::encode(tx.clone()))], - "id": self.network().chain_id() - })) - .map_err(|_| EthApiError::InternalEthError)?; - - let client = reqwest::Client::new(); - - client - .post(endpoint) - .header(CONTENT_TYPE, "application/json") - .body(body) - .send() - .await - .map_err(|_| EthApiError::InternalEthError)?; - } + self.forward_to_sequencer(&tx).await?; let recovered = recover_raw_transaction(tx)?; let pool_transaction = ::from_recovered_transaction(recovered); @@ -880,7 +862,7 @@ impl EthApi where Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: 'static, + Network: NetworkInfo + 'static, { /// Helper function for `eth_getTransactionReceipt` /// @@ -956,6 +938,34 @@ where l1_data_gas, ) } + + /// Helper function for `eth_send_raw_transaction` for Optimism. + /// + /// Forwards the raw transaction bytes to the configured sequencer endpoint. + /// This is a no-op if the sequencer endpoint is not configured. + #[cfg(feature = "optimism")] + pub async fn forward_to_sequencer(&self, tx: &Bytes) -> EthResult<()> { + if let Some(endpoint) = self.network().sequencer_endpoint() { + let body = serde_json::to_string(&serde_json::json!({ + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": [format!("0x{}", hex::encode(tx))], + "id": self.network().chain_id() + })) + .map_err(|_| EthApiError::InternalEthError)?; + + let client = reqwest::Client::new(); + + client + .post(endpoint) + .header(CONTENT_TYPE, "application/json") + .body(body) + .send() + .await + .map_err(|_| EthApiError::InternalEthError)?; + } + Ok(()) + } } impl EthApi diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index 6c151b51fafa..91ddb7cd86b4 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -324,6 +324,16 @@ pub enum RpcInvalidTransactionError { /// Blob transaction is a create transaction #[error("blob transaction is a create transaction")] BlobTransactionIsCreate, + /// Optimism related error + #[error(transparent)] + #[cfg(feature = "optimism")] + Optimism(#[from] OptimismInvalidTransactionError), +} + +/// Optimism specific invalid transaction errors +#[cfg(feature = "optimism")] +#[derive(thiserror::Error, Debug)] +pub enum OptimismInvalidTransactionError { /// A deposit transaction was submitted as a system transaction post-regolith. #[error("no system transactions allowed after regolith")] #[cfg(feature = "optimism")] @@ -442,12 +452,14 @@ impl From for RpcInvalidTransactionError { } #[cfg(feature = "optimism")] InvalidTransaction::DepositSystemTxPostRegolith => { - RpcInvalidTransactionError::DepositSystemTxPostRegolith + RpcInvalidTransactionError::Optimism( + OptimismInvalidTransactionError::DepositSystemTxPostRegolith, + ) } #[cfg(feature = "optimism")] - InvalidTransaction::HaltedDepositPostRegolith => { - RpcInvalidTransactionError::HaltedDepositPostRegolith - } + InvalidTransaction::HaltedDepositPostRegolith => RpcInvalidTransactionError::Optimism( + OptimismInvalidTransactionError::HaltedDepositPostRegolith, + ), } } }