Skip to main content

near_api/common/
send.rs

1// Boxing `ExecuteTransactionError` would break the public API.
2#![allow(clippy::result_large_err)]
3
4use std::fmt;
5use std::sync::Arc;
6
7use near_openapi_client::types::{
8    ErrorWrapperForRpcTransactionError, FinalExecutionOutcomeView, JsonRpcRequestForSendTx,
9    JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError, RpcSendTransactionRequest,
10    RpcTransactionError, RpcTransactionResponse,
11};
12
13use near_api_types::{
14    BlockHeight, CryptoHash, Nonce, PublicKey, TxExecutionStatus,
15    transaction::{
16        PrepopulateTransaction, SignedTransaction,
17        delegate_action::{SignedDelegateAction, SignedDelegateActionAsBase64},
18        result::{ExecutionFinalResult, TransactionResult},
19    },
20};
21use reqwest::Response;
22use tracing::{debug, info};
23
24use crate::{
25    common::utils::{is_critical_transaction_error, to_retry_error},
26    config::{NetworkConfig, RetryResponse, retry},
27    errors::{
28        ArgumentValidationError, ExecuteMetaTransactionsError, ExecuteTransactionError,
29        MetaSignError, SendRequestError, SignerError, ValidationError,
30    },
31    signer::Signer,
32};
33
34use super::META_TRANSACTION_VALID_FOR_DEFAULT;
35
36const TX_EXECUTOR_TARGET: &str = "near_api::tx::executor";
37const META_EXECUTOR_TARGET: &str = "near_api::meta::executor";
38
39/// Internal enum to distinguish between a full RPC response and a minimal pending response.
40enum SendImplResponse {
41    Full(Box<RpcTransactionResponse>),
42    Pending(TxExecutionStatus),
43}
44
45impl fmt::Debug for SendImplResponse {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Self::Full(_) => write!(f, "Full(...)"),
49            Self::Pending(status) => write!(f, "Pending({status:?})"),
50        }
51    }
52}
53
54/// Minimal JSON-RPC response returned when `wait_until` is `NONE` or `INCLUDED`.
55///
56/// The RPC returns only `{"jsonrpc":"2.0","result":{"final_execution_status":"..."},"id":"0"}`
57/// which doesn't match the full `RpcTransactionResponse` schema.
58#[derive(serde::Deserialize)]
59struct MinimalTransactionResponse {
60    result: MinimalTransactionResult,
61}
62
63#[derive(serde::Deserialize)]
64struct MinimalTransactionResult {
65    final_execution_status: TxExecutionStatus,
66}
67
68#[async_trait::async_trait]
69pub trait Transactionable: Send + Sync {
70    fn prepopulated(&self) -> Result<PrepopulateTransaction, ArgumentValidationError>;
71
72    /// Validate the transaction before sending it to the network
73    async fn validate_with_network(&self, network: &NetworkConfig) -> Result<(), ValidationError>;
74
75    /// Edit the transaction before sending it to the network.
76    /// This is useful for example to add storage deposit to the transaction
77    /// if it's needed.
78    /// Though, it won't be called if the user has presigned the transaction.
79    async fn edit_with_network(&mut self, _network: &NetworkConfig) -> Result<(), ValidationError> {
80        Ok(())
81    }
82}
83
84pub enum TransactionableOrSigned<Signed> {
85    /// A transaction that is not signed.
86    Transactionable(Box<dyn Transactionable + 'static>),
87    /// A transaction that is signed and ready to be sent to the network.
88    Signed((Signed, Box<dyn Transactionable + 'static>)),
89}
90
91impl<Signed> TransactionableOrSigned<Signed> {
92    pub fn signed(self) -> Option<Signed> {
93        match self {
94            Self::Signed((signed, _)) => Some(signed),
95            Self::Transactionable(_) => None,
96        }
97    }
98}
99
100impl<S> TransactionableOrSigned<S> {
101    pub fn transactionable(self) -> Box<dyn Transactionable> {
102        match self {
103            Self::Transactionable(transaction) => transaction,
104            Self::Signed((_, transaction)) => transaction,
105        }
106    }
107}
108
109/// The handler for signing and sending transaction to the network.
110///
111/// This is the main entry point for the transaction sending functionality.
112pub struct ExecuteSignedTransaction {
113    /// The transaction that is either not signed yet or already signed.
114    pub transaction: TransactionableOrSigned<SignedTransaction>,
115    /// The signer that will be used to sign the transaction.
116    pub signer: Arc<Signer>,
117
118    pub wait_until: TxExecutionStatus,
119}
120
121impl ExecuteSignedTransaction {
122    pub fn new<T: Transactionable + 'static>(transaction: T, signer: Arc<Signer>) -> Self {
123        Self {
124            transaction: TransactionableOrSigned::Transactionable(Box::new(transaction)),
125            signer,
126            wait_until: TxExecutionStatus::Final,
127        }
128    }
129
130    /// Changes the transaction to a [meta transaction](https://docs.near.org/concepts/abstraction/meta-transactions), allowing some 3rd party entity to execute it and
131    /// pay for the gas.
132    ///
133    /// Please note, that if you already presigned the transaction, it would require you to sign it again as a meta transaction
134    /// is a different type of transaction.
135    pub fn meta(self) -> ExecuteMetaTransaction {
136        ExecuteMetaTransaction::from_box(self.transaction.transactionable(), self.signer)
137    }
138
139    pub const fn wait_until(mut self, wait_until: TxExecutionStatus) -> Self {
140        self.wait_until = wait_until;
141        self
142    }
143
144    /// Signs the transaction offline without fetching the nonce or block hash from the network.
145    ///
146    /// The transaction won't be broadcasted to the network and just stored signed in the [Self::transaction] struct variable.
147    ///
148    /// This is useful if you already have the nonce and block hash, or if you want to sign the transaction
149    /// offline. Please note that incorrect nonce will lead to transaction failure.
150    pub async fn presign_offline(
151        mut self,
152        public_key: PublicKey,
153        block_hash: CryptoHash,
154        nonce: Nonce,
155    ) -> Result<Self, ExecuteTransactionError> {
156        let transaction = match &self.transaction {
157            TransactionableOrSigned::Transactionable(transaction) => transaction,
158            TransactionableOrSigned::Signed(_) => return Ok(self),
159        };
160
161        let transaction = transaction.prepopulated()?;
162
163        let signed_tr = self
164            .signer
165            .sign(transaction, public_key, nonce, block_hash)
166            .await?;
167
168        self.transaction =
169            TransactionableOrSigned::Signed((signed_tr, self.transaction.transactionable()));
170        Ok(self)
171    }
172
173    /// Signs the transaction with the custom network configuration but doesn't broadcast it.
174    ///
175    /// Signed transaction is stored in the [Self::transaction] struct variable.
176    ///
177    /// This is useful if you want to sign with non-default network configuration (e.g, custom RPC URL, sandbox).
178    /// The provided call will fetch the nonce and block hash from the given network.
179    pub async fn presign_with(
180        self,
181        network: &NetworkConfig,
182    ) -> Result<Self, ExecuteTransactionError> {
183        let transaction = match &self.transaction {
184            TransactionableOrSigned::Transactionable(transaction) => transaction,
185            TransactionableOrSigned::Signed(_) => return Ok(self),
186        };
187
188        let transaction = transaction.prepopulated()?;
189
190        let signer_key = self
191            .signer
192            .get_public_key()
193            .await
194            .map_err(SignerError::from)?;
195        let (nonce, hash, _) = self
196            .signer
197            .fetch_tx_nonce(transaction.signer_id.clone(), signer_key, network)
198            .await
199            .map_err(MetaSignError::from)?;
200        self.presign_offline(signer_key, hash, nonce).await
201    }
202
203    /// Signs the transaction with the default mainnet configuration. Does not broadcast it.
204    ///
205    /// Signed transaction is stored in the [Self::transaction] struct variable.
206    ///
207    /// The provided call will fetch the nonce and block hash from the network.
208    pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteTransactionError> {
209        let network = NetworkConfig::mainnet();
210        self.presign_with(&network).await
211    }
212
213    /// Signs the transaction with the default testnet configuration. Does not broadcast it.
214    ///
215    /// Signed transaction is stored in the [Self::transaction] struct variable.
216    ///
217    /// The provided call will fetch the nonce and block hash from the network.
218    pub async fn presign_with_testnet(self) -> Result<Self, ExecuteTransactionError> {
219        let network = NetworkConfig::testnet();
220        self.presign_with(&network).await
221    }
222
223    /// Sends the transaction to the custom provided network.
224    ///
225    /// This is useful if you want to send the transaction to a non-default network configuration (e.g, custom RPC URL, sandbox).
226    /// Please note that if the transaction is not presigned, it will be signed with the network's nonce and block hash.
227    ///
228    /// Returns a [`TransactionResult`] which is either:
229    /// - [`TransactionResult::Pending`] if `wait_until` is `None` or `Included` (no execution data available yet)
230    /// - [`TransactionResult::Full`] for higher finality levels with full execution results
231    pub async fn send_to(
232        mut self,
233        network: &NetworkConfig,
234    ) -> Result<TransactionResult, ExecuteTransactionError> {
235        let (signed, transactionable) = match &mut self.transaction {
236            TransactionableOrSigned::Transactionable(transaction) => {
237                debug!(target: TX_EXECUTOR_TARGET, "Preparing unsigned transaction");
238                (None, transaction)
239            }
240            TransactionableOrSigned::Signed((s, transaction)) => {
241                debug!(target: TX_EXECUTOR_TARGET, "Using pre-signed transaction");
242                (Some(s.clone()), transaction)
243            }
244        };
245
246        let wait_until = self.wait_until;
247
248        if signed.is_none() {
249            debug!(target: TX_EXECUTOR_TARGET, "Editing transaction with network config");
250            transactionable.edit_with_network(network).await?;
251        } else {
252            debug!(target: TX_EXECUTOR_TARGET, "Validating pre-signed transaction with network config");
253            transactionable.validate_with_network(network).await?;
254        }
255
256        let signed = match signed {
257            Some(s) => s,
258            None => {
259                debug!(target: TX_EXECUTOR_TARGET, "Signing transaction");
260                self.presign_with(network)
261                    .await?
262                    .transaction
263                    .signed()
264                    .expect("Expect to have it signed")
265            }
266        };
267
268        info!(
269            target: TX_EXECUTOR_TARGET,
270            "Broadcasting signed transaction. Hash: {:?}, Signer: {:?}, Receiver: {:?}, Nonce: {}",
271            signed.get_hash(),
272            signed.transaction.signer_id(),
273            signed.transaction.receiver_id(),
274            signed.transaction.nonce(),
275        );
276
277        Self::send_impl(network, signed, wait_until).await
278    }
279
280    /// Sends the transaction to the default mainnet configuration.
281    ///
282    /// Please note that this will sign the transaction with the mainnet's nonce and block hash if it's not presigned yet.
283    pub async fn send_to_mainnet(self) -> Result<TransactionResult, ExecuteTransactionError> {
284        let network = NetworkConfig::mainnet();
285        self.send_to(&network).await
286    }
287
288    /// Sends the transaction to the default testnet configuration.
289    ///
290    /// Please note that this will sign the transaction with the testnet's nonce and block hash if it's not presigned yet.
291    pub async fn send_to_testnet(self) -> Result<TransactionResult, ExecuteTransactionError> {
292        let network = NetworkConfig::testnet();
293        self.send_to(&network).await
294    }
295
296    async fn send_impl(
297        network: &NetworkConfig,
298        signed_tr: SignedTransaction,
299        wait_until: TxExecutionStatus,
300    ) -> Result<TransactionResult, ExecuteTransactionError> {
301        let hash = signed_tr.get_hash();
302        let signed_tx_base64: near_openapi_client::types::SignedTransaction = signed_tr.into();
303        let result = retry(network.clone(), |client| {
304            let signed_tx_base64 = signed_tx_base64.clone();
305            async move {
306                let result = match client
307                    .send_tx(&JsonRpcRequestForSendTx {
308                        id: "0".to_string(),
309                        jsonrpc: "2.0".to_string(),
310                        method: near_openapi_client::types::JsonRpcRequestForSendTxMethod::SendTx,
311                        params: RpcSendTransactionRequest {
312                            signed_tx_base64,
313                            wait_until,
314                        },
315                    })
316                    .await
317                    .map(|r| r.into_inner())
318                    .map_err(SendRequestError::from)
319                {
320                    Ok(
321                        JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant0 {
322                            result,
323                            ..
324                        },
325                    ) => RetryResponse::Ok(SendImplResponse::Full(Box::new(result))),
326                    Ok(
327                        JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant1 {
328                            error,
329                            ..
330                        },
331                    ) => {
332                        let error: SendRequestError<RpcTransactionError> =
333                            SendRequestError::from(error);
334                        to_retry_error(error, is_critical_transaction_error)
335                    }
336                    Err(err) => {
337                        // When wait_until is NONE or INCLUDED, the RPC returns a minimal
338                        // response with only `final_execution_status`. The openapi client
339                        // fails to deserialize this into RpcTransactionResponse (which
340                        // expects full execution data) and returns InvalidResponsePayload.
341                        // We intercept this case and parse the minimal response ourselves.
342                        //
343                        // We only attempt this fallback when we explicitly requested a
344                        // minimal response, so unexpected/buggy RPC responses for higher
345                        // finality levels don't get silently treated as Pending.
346                        if matches!(
347                            wait_until,
348                            TxExecutionStatus::None | TxExecutionStatus::Included
349                        ) {
350                            if let SendRequestError::TransportError(
351                                near_openapi_client::Error::InvalidResponsePayload(ref bytes, _),
352                            ) = err
353                            {
354                                if let Ok(minimal) =
355                                    serde_json::from_slice::<MinimalTransactionResponse>(bytes)
356                                {
357                                    return RetryResponse::Ok(SendImplResponse::Pending(
358                                        minimal.result.final_execution_status,
359                                    ));
360                                }
361                            }
362                        }
363                        to_retry_error(err, is_critical_transaction_error)
364                    }
365                };
366
367                tracing::debug!(
368                    target: TX_EXECUTOR_TARGET,
369                    "Broadcasting transaction {} resulted in {:?}",
370                    hash,
371                    result
372                );
373
374                result
375            }
376        })
377        .await
378        .map_err(ExecuteTransactionError::TransactionError)?;
379
380        match result {
381            SendImplResponse::Pending(status) => Ok(TransactionResult::Pending { status }),
382            SendImplResponse::Full(rpc_response) => {
383                let final_execution_outcome_view = to_final_execution_outcome(*rpc_response);
384
385                Ok(TransactionResult::Full(Box::new(
386                    ExecutionFinalResult::try_from(final_execution_outcome_view)?,
387                )))
388            }
389        }
390    }
391}
392
393pub struct ExecuteMetaTransaction {
394    pub transaction: TransactionableOrSigned<SignedDelegateAction>,
395    pub signer: Arc<Signer>,
396    pub tx_live_for: Option<BlockHeight>,
397}
398
399impl ExecuteMetaTransaction {
400    pub fn new<T: Transactionable + 'static>(transaction: T, signer: Arc<Signer>) -> Self {
401        Self {
402            transaction: TransactionableOrSigned::Transactionable(Box::new(transaction)),
403            signer,
404            tx_live_for: None,
405        }
406    }
407
408    pub fn from_box(transaction: Box<dyn Transactionable + 'static>, signer: Arc<Signer>) -> Self {
409        Self {
410            transaction: TransactionableOrSigned::Transactionable(transaction),
411            signer,
412            tx_live_for: None,
413        }
414    }
415
416    /// Sets the transaction live for the given block amount.
417    ///
418    /// This is useful if you want to set the transaction to be valid for a specific amount of blocks.\
419    /// The default amount is 1000 blocks.
420    pub const fn tx_live_for(mut self, tx_live_for: BlockHeight) -> Self {
421        self.tx_live_for = Some(tx_live_for);
422        self
423    }
424
425    /// Signs the transaction offline without fetching the nonce or block hash from the network. Does not broadcast it.
426    ///
427    /// Signed transaction is stored in the [Self::transaction] struct variable.
428    ///
429    /// This is useful if you already have the nonce and block hash, or if you want to sign the transaction
430    /// offline. Please note that incorrect nonce will lead to transaction failure and incorrect block height
431    /// will lead to incorrectly populated transaction live value.
432    pub async fn presign_offline(
433        mut self,
434        signer_key: PublicKey,
435        block_hash: CryptoHash,
436        nonce: Nonce,
437        block_height: BlockHeight,
438    ) -> Result<Self, ExecuteMetaTransactionsError> {
439        let transaction = match &self.transaction {
440            TransactionableOrSigned::Transactionable(transaction) => transaction,
441            TransactionableOrSigned::Signed(_) => return Ok(self),
442        };
443
444        let transaction = transaction.prepopulated()?;
445        let max_block_height = block_height
446            + self
447                .tx_live_for
448                .unwrap_or(META_TRANSACTION_VALID_FOR_DEFAULT);
449
450        let signed_tr = self
451            .signer
452            .sign_meta(transaction, signer_key, nonce, block_hash, max_block_height)
453            .await?;
454
455        self.transaction =
456            TransactionableOrSigned::Signed((signed_tr, self.transaction.transactionable()));
457        Ok(self)
458    }
459
460    /// Signs the transaction with the custom network configuration but doesn't broadcast it.
461    ///
462    /// Signed transaction is stored in the [Self::transaction] struct variable.
463    ///
464    /// This is useful if you want to sign with non-default network configuration (e.g, custom RPC URL, sandbox).
465    pub async fn presign_with(
466        self,
467        network: &NetworkConfig,
468    ) -> Result<Self, ExecuteMetaTransactionsError> {
469        let transaction = match &self.transaction {
470            TransactionableOrSigned::Transactionable(transaction) => transaction,
471            TransactionableOrSigned::Signed(_) => return Ok(self),
472        };
473
474        let transaction = transaction.prepopulated()?;
475        let signer_key = self
476            .signer
477            .get_public_key()
478            .await
479            .map_err(SignerError::from)
480            .map_err(MetaSignError::from)?;
481        let (nonce, block_hash, block_height) = self
482            .signer
483            .fetch_tx_nonce(transaction.signer_id.clone(), signer_key, network)
484            .await
485            .map_err(MetaSignError::from)?;
486        self.presign_offline(signer_key, block_hash, nonce, block_height)
487            .await
488    }
489
490    /// Signs the transaction with the default mainnet configuration but doesn't broadcast it.
491    ///
492    /// Signed transaction is stored in the [Self::transaction] struct variable.
493    ///
494    /// The provided call will fetch the nonce and block hash, block height from the network.
495    pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
496        let network = NetworkConfig::mainnet();
497        self.presign_with(&network).await
498    }
499
500    /// Signs the transaction with the default testnet configuration but doesn't broadcast it.
501    ///
502    /// Signed transaction is stored in the [Self::transaction] struct variable.
503    ///
504    /// The provided call will fetch the nonce and block hash, block height from the network.
505    pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
506        let network = NetworkConfig::testnet();
507        self.presign_with(&network).await
508    }
509
510    /// Sends the transaction to the custom provided network.
511    ///
512    /// This is useful if you want to send the transaction to a non-default network configuration (e.g, custom RPC URL, sandbox).
513    /// Please note that if the transaction is not presigned, it will be sign with the network's nonce and block hash.
514    pub async fn send_to(
515        mut self,
516        network: &NetworkConfig,
517    ) -> Result<Response, ExecuteMetaTransactionsError> {
518        let (signed, transactionable) = match &mut self.transaction {
519            TransactionableOrSigned::Transactionable(transaction) => {
520                debug!(target: META_EXECUTOR_TARGET, "Preparing unsigned meta transaction");
521                (None, transaction)
522            }
523            TransactionableOrSigned::Signed((s, transaction)) => {
524                debug!(target: META_EXECUTOR_TARGET, "Using pre-signed meta transaction");
525                (Some(s.clone()), transaction)
526            }
527        };
528
529        if signed.is_none() {
530            debug!(target: META_EXECUTOR_TARGET, "Editing meta transaction with network config");
531            transactionable.edit_with_network(network).await?;
532        } else {
533            debug!(target: META_EXECUTOR_TARGET, "Validating pre-signed meta transaction with network config");
534            transactionable.validate_with_network(network).await?;
535        }
536
537        let signed = match signed {
538            Some(s) => s,
539            None => {
540                debug!(target: META_EXECUTOR_TARGET, "Signing meta transaction");
541                self.presign_with(network)
542                    .await?
543                    .transaction
544                    .signed()
545                    .expect("Expect to have it signed")
546            }
547        };
548
549        info!(
550            target: META_EXECUTOR_TARGET,
551            "Broadcasting signed meta transaction. Signer: {:?}, Receiver: {:?}, Nonce: {}, Valid until: {}",
552            signed.delegate_action.sender_id,
553            signed.delegate_action.receiver_id,
554            signed.delegate_action.nonce,
555            signed.delegate_action.max_block_height
556        );
557
558        Self::send_impl(network, signed).await
559    }
560
561    /// Sends the transaction to the default mainnet configuration.
562    ///
563    /// Please note that this will sign the transaction with the mainnet's nonce and block hash if it's not presigned yet.
564    pub async fn send_to_mainnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
565        let network = NetworkConfig::mainnet();
566        self.send_to(&network).await
567    }
568
569    /// Sends the transaction to the default testnet configuration.
570    ///
571    /// Please note that this will sign the transaction with the testnet's nonce and block hash if it's not presigned yet.
572    pub async fn send_to_testnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
573        let network = NetworkConfig::testnet();
574        self.send_to(&network).await
575    }
576
577    async fn send_impl(
578        network: &NetworkConfig,
579        transaction: SignedDelegateAction,
580    ) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
581        let client = reqwest::Client::new();
582        let json_payload = serde_json::json!({
583            "signed_delegate_action": SignedDelegateActionAsBase64::from(
584                transaction.clone()
585            ).to_string(),
586        });
587        debug!(
588            target: META_EXECUTOR_TARGET,
589            "Sending meta transaction to relayer. Payload: {:?}",
590            json_payload
591        );
592        let resp = client
593            .post(
594                network
595                    .meta_transaction_relayer_url
596                    .clone()
597                    .ok_or(ExecuteMetaTransactionsError::RelayerIsNotDefined)?,
598            )
599            .json(&json_payload)
600            .send()
601            .await?;
602
603        info!(
604            target: META_EXECUTOR_TARGET,
605            "Meta transaction sent to relayer. Status: {}, Signer: {:?}, Receiver: {:?}",
606            resp.status(),
607            transaction.delegate_action.sender_id,
608            transaction.delegate_action.receiver_id
609        );
610        Ok(resp)
611    }
612}
613
614/// Extracts a [`FinalExecutionOutcomeView`] from an [`RpcTransactionResponse`].
615///
616/// Both `send_tx` and `tx` (status query) responses share the same envelope type.
617/// This function strips the `final_execution_status` and optional `receipts` fields
618/// that are not part of `FinalExecutionOutcomeView`.
619// TODO: check if we need to add support for `final_execution_status`
620pub fn to_final_execution_outcome(response: RpcTransactionResponse) -> FinalExecutionOutcomeView {
621    match response {
622        RpcTransactionResponse::Variant0 {
623            final_execution_status: _,
624            receipts: _,
625            receipts_outcome,
626            status,
627            transaction,
628            transaction_outcome,
629        } => FinalExecutionOutcomeView {
630            receipts_outcome,
631            status,
632            transaction,
633            transaction_outcome,
634        },
635        RpcTransactionResponse::Variant1 {
636            final_execution_status: _,
637            receipts_outcome,
638            status,
639            transaction,
640            transaction_outcome,
641        } => FinalExecutionOutcomeView {
642            receipts_outcome,
643            status,
644            transaction,
645            transaction_outcome,
646        },
647    }
648}
649
650impl From<ErrorWrapperForRpcTransactionError> for SendRequestError<RpcTransactionError> {
651    fn from(err: ErrorWrapperForRpcTransactionError) -> Self {
652        match err {
653            ErrorWrapperForRpcTransactionError::InternalError(internal_error) => {
654                Self::InternalError(internal_error)
655            }
656            ErrorWrapperForRpcTransactionError::RequestValidationError(
657                rpc_request_validation_error_kind,
658            ) => Self::RequestValidationError(rpc_request_validation_error_kind),
659            ErrorWrapperForRpcTransactionError::HandlerError(server_error) => {
660                Self::ServerError(server_error)
661            }
662        }
663    }
664}