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
36enum 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#[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 async fn validate_with_network(&self, network: &NetworkConfig) -> Result<(), ValidationError>;
71
72 async fn edit_with_network(&mut self, _network: &NetworkConfig) -> Result<(), ValidationError> {
77 Ok(())
78 }
79}
80
81pub enum TransactionableOrSigned<Signed> {
82 Transactionable(Box<dyn Transactionable + 'static>),
84 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
106pub struct ExecuteSignedTransaction {
110 pub transaction: TransactionableOrSigned<SignedTransaction>,
112 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 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 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 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 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteTransactionError> {
206 let network = NetworkConfig::mainnet();
207 self.presign_with(&network).await
208 }
209
210 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteTransactionError> {
216 let network = NetworkConfig::testnet();
217 self.presign_with(&network).await
218 }
219
220 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 pub async fn send_to_mainnet(self) -> Result<TransactionResult, ExecuteTransactionError> {
281 let network = NetworkConfig::mainnet();
282 self.send_to(&network).await
283 }
284
285 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 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 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 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 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 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
493 let network = NetworkConfig::mainnet();
494 self.presign_with(&network).await
495 }
496
497 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
503 let network = NetworkConfig::testnet();
504 self.presign_with(&network).await
505 }
506
507 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 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 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
611pub 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}