Skip to main content

near_api/common/
send.rs

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