1#![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
39enum 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#[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 async fn validate_with_network(&self, network: &NetworkConfig) -> Result<(), ValidationError>;
74
75 async fn edit_with_network(&mut self, _network: &NetworkConfig) -> Result<(), ValidationError> {
80 Ok(())
81 }
82}
83
84pub enum TransactionableOrSigned<Signed> {
85 Transactionable(Box<dyn Transactionable + 'static>),
87 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
109pub struct ExecuteSignedTransaction {
113 pub transaction: TransactionableOrSigned<SignedTransaction>,
115 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 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 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 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 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteTransactionError> {
209 let network = NetworkConfig::mainnet();
210 self.presign_with(&network).await
211 }
212
213 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteTransactionError> {
219 let network = NetworkConfig::testnet();
220 self.presign_with(&network).await
221 }
222
223 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 pub async fn send_to_mainnet(self) -> Result<TransactionResult, ExecuteTransactionError> {
284 let network = NetworkConfig::mainnet();
285 self.send_to(&network).await
286 }
287
288 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 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 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 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 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 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
496 let network = NetworkConfig::mainnet();
497 self.presign_with(&network).await
498 }
499
500 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
506 let network = NetworkConfig::testnet();
507 self.presign_with(&network).await
508 }
509
510 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 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 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
614pub 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}