1use std::sync::Arc;
2
3use near_openapi_client::types::{
4 ErrorWrapperForRpcTransactionError, FinalExecutionOutcomeView, JsonRpcRequestForSendTx,
5 JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError, RpcSendTransactionRequest,
6 RpcTransactionError, RpcTransactionResponse,
7};
8
9use near_api_types::{
10 transaction::{
11 delegate_action::{SignedDelegateAction, SignedDelegateActionAsBase64},
12 result::ExecutionFinalResult,
13 PrepopulateTransaction, SignedTransaction,
14 },
15 BlockHeight, CryptoHash, Nonce, PublicKey, TxExecutionStatus,
16};
17use reqwest::Response;
18use tracing::{debug, info};
19
20use crate::{
21 common::utils::{is_critical_transaction_error, to_retry_error},
22 config::{retry, NetworkConfig, RetryResponse},
23 errors::{
24 ArgumentValidationError, ExecuteMetaTransactionsError, ExecuteTransactionError,
25 MetaSignError, SendRequestError, SignerError, ValidationError,
26 },
27 signer::Signer,
28};
29
30use super::META_TRANSACTION_VALID_FOR_DEFAULT;
31
32const TX_EXECUTOR_TARGET: &str = "near_api::tx::executor";
33const META_EXECUTOR_TARGET: &str = "near_api::meta::executor";
34
35#[async_trait::async_trait]
36pub trait Transactionable: Send + Sync {
37 fn prepopulated(&self) -> Result<PrepopulateTransaction, ArgumentValidationError>;
38
39 async fn validate_with_network(&self, network: &NetworkConfig) -> Result<(), ValidationError>;
41
42 async fn edit_with_network(&mut self, _network: &NetworkConfig) -> Result<(), ValidationError> {
47 Ok(())
48 }
49}
50
51pub enum TransactionableOrSigned<Signed> {
52 Transactionable(Box<dyn Transactionable + 'static>),
54 Signed((Signed, Box<dyn Transactionable + 'static>)),
56}
57
58impl<Signed> TransactionableOrSigned<Signed> {
59 pub fn signed(self) -> Option<Signed> {
60 match self {
61 Self::Signed((signed, _)) => Some(signed),
62 Self::Transactionable(_) => None,
63 }
64 }
65}
66
67impl<S> TransactionableOrSigned<S> {
68 pub fn transactionable(self) -> Box<dyn Transactionable> {
69 match self {
70 Self::Transactionable(transaction) => transaction,
71 Self::Signed((_, transaction)) => transaction,
72 }
73 }
74}
75
76pub struct ExecuteSignedTransaction {
80 pub transaction: TransactionableOrSigned<SignedTransaction>,
82 pub signer: Arc<Signer>,
84
85 pub wait_until: TxExecutionStatus,
86}
87
88impl ExecuteSignedTransaction {
89 pub fn new<T: Transactionable + 'static>(transaction: T, signer: Arc<Signer>) -> Self {
90 Self {
91 transaction: TransactionableOrSigned::Transactionable(Box::new(transaction)),
92 signer,
93 wait_until: TxExecutionStatus::Final,
94 }
95 }
96
97 pub fn meta(self) -> ExecuteMetaTransaction {
103 ExecuteMetaTransaction::from_box(self.transaction.transactionable(), self.signer)
104 }
105
106 pub const fn wait_until(mut self, wait_until: TxExecutionStatus) -> Self {
107 self.wait_until = wait_until;
108 self
109 }
110
111 pub async fn presign_offline(
118 mut self,
119 public_key: PublicKey,
120 block_hash: CryptoHash,
121 nonce: Nonce,
122 ) -> Result<Self, ExecuteTransactionError> {
123 let transaction = match &self.transaction {
124 TransactionableOrSigned::Transactionable(transaction) => transaction,
125 TransactionableOrSigned::Signed(_) => return Ok(self),
126 };
127
128 let transaction = transaction.prepopulated()?;
129
130 let signed_tr = self
131 .signer
132 .sign(transaction, public_key, nonce, block_hash)
133 .await?;
134
135 self.transaction =
136 TransactionableOrSigned::Signed((signed_tr, self.transaction.transactionable()));
137 Ok(self)
138 }
139
140 pub async fn presign_with(
147 self,
148 network: &NetworkConfig,
149 ) -> Result<Self, ExecuteTransactionError> {
150 let transaction = match &self.transaction {
151 TransactionableOrSigned::Transactionable(transaction) => transaction,
152 TransactionableOrSigned::Signed(_) => return Ok(self),
153 };
154
155 let transaction = transaction.prepopulated()?;
156
157 let signer_key = self
158 .signer
159 .get_public_key()
160 .await
161 .map_err(SignerError::from)?;
162 let (nonce, hash, _) = self
163 .signer
164 .fetch_tx_nonce(transaction.signer_id.clone(), signer_key, network)
165 .await
166 .map_err(MetaSignError::from)?;
167 self.presign_offline(signer_key, hash, nonce).await
168 }
169
170 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteTransactionError> {
176 let network = NetworkConfig::mainnet();
177 self.presign_with(&network).await
178 }
179
180 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteTransactionError> {
186 let network = NetworkConfig::testnet();
187 self.presign_with(&network).await
188 }
189
190 pub async fn send_to(
195 mut self,
196 network: &NetworkConfig,
197 ) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
198 let (signed, transactionable) = match &mut self.transaction {
199 TransactionableOrSigned::Transactionable(transaction) => {
200 debug!(target: TX_EXECUTOR_TARGET, "Preparing unsigned transaction");
201 (None, transaction)
202 }
203 TransactionableOrSigned::Signed((s, transaction)) => {
204 debug!(target: TX_EXECUTOR_TARGET, "Using pre-signed transaction");
205 (Some(s.clone()), transaction)
206 }
207 };
208
209 let wait_until = self.wait_until;
210
211 if signed.is_none() {
212 debug!(target: TX_EXECUTOR_TARGET, "Editing transaction with network config");
213 transactionable.edit_with_network(network).await?;
214 } else {
215 debug!(target: TX_EXECUTOR_TARGET, "Validating pre-signed transaction with network config");
216 transactionable.validate_with_network(network).await?;
217 }
218
219 let signed = match signed {
220 Some(s) => s,
221 None => {
222 debug!(target: TX_EXECUTOR_TARGET, "Signing transaction");
223 self.presign_with(network)
224 .await?
225 .transaction
226 .signed()
227 .expect("Expect to have it signed")
228 }
229 };
230
231 info!(
232 target: TX_EXECUTOR_TARGET,
233 "Broadcasting signed transaction. Hash: {:?}, Signer: {:?}, Receiver: {:?}, Nonce: {}",
234 signed.get_hash(),
235 signed.transaction.signer_id(),
236 signed.transaction.receiver_id(),
237 signed.transaction.nonce(),
238 );
239
240 Self::send_impl(network, signed, wait_until).await
241 }
242
243 pub async fn send_to_mainnet(self) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
247 let network = NetworkConfig::mainnet();
248 self.send_to(&network).await
249 }
250
251 pub async fn send_to_testnet(self) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
255 let network = NetworkConfig::testnet();
256 self.send_to(&network).await
257 }
258
259 async fn send_impl(
260 network: &NetworkConfig,
261 signed_tr: SignedTransaction,
262 wait_until: TxExecutionStatus,
263 ) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
264 let hash = signed_tr.get_hash();
265 let signed_tx_base64: near_openapi_client::types::SignedTransaction = signed_tr.into();
266 let result = retry(network.clone(), |client| {
267 let signed_tx_base64 = signed_tx_base64.clone();
268 async move {
269 let result = match client
270 .send_tx(&JsonRpcRequestForSendTx {
271 id: "0".to_string(),
272 jsonrpc: "2.0".to_string(),
273 method: near_openapi_client::types::JsonRpcRequestForSendTxMethod::SendTx,
274 params: RpcSendTransactionRequest {
275 signed_tx_base64,
276 wait_until,
277 },
278 })
279 .await
280 .map(|r| r.into_inner())
281 .map_err(SendRequestError::from)
282 {
283 Ok(
284 JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant0 {
285 result,
286 ..
287 },
288 ) => RetryResponse::Ok(result),
289 Ok(
290 JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant1 {
291 error,
292 ..
293 },
294 ) => {
295 let error: SendRequestError<RpcTransactionError> =
296 SendRequestError::from(error);
297 to_retry_error(error, is_critical_transaction_error)
298 }
299 Err(err) => to_retry_error(err, is_critical_transaction_error),
300 };
301
302 tracing::debug!(
303 target: TX_EXECUTOR_TARGET,
304 "Broadcasting transaction {} resulted in {:?}",
305 hash,
306 result
307 );
308
309 result
310 }
311 })
312 .await
313 .map_err(ExecuteTransactionError::TransactionError)?;
314
315 let final_execution_outcome_view = match result {
317 RpcTransactionResponse::Variant0 {
319 final_execution_status: _,
320 receipts: _,
321 receipts_outcome,
322 status,
323 transaction,
324 transaction_outcome,
325 } => FinalExecutionOutcomeView {
326 receipts_outcome,
327 status,
328 transaction,
329 transaction_outcome,
330 },
331 RpcTransactionResponse::Variant1 {
332 final_execution_status: _,
333 receipts_outcome,
334 status,
335 transaction,
336 transaction_outcome,
337 } => FinalExecutionOutcomeView {
338 receipts_outcome,
339 status,
340 transaction,
341 transaction_outcome,
342 },
343 };
344
345 Ok(ExecutionFinalResult::try_from(
346 final_execution_outcome_view,
347 )?)
348 }
349}
350
351pub struct ExecuteMetaTransaction {
352 pub transaction: TransactionableOrSigned<SignedDelegateAction>,
353 pub signer: Arc<Signer>,
354 pub tx_live_for: Option<BlockHeight>,
355}
356
357impl ExecuteMetaTransaction {
358 pub fn new<T: Transactionable + 'static>(transaction: T, signer: Arc<Signer>) -> Self {
359 Self {
360 transaction: TransactionableOrSigned::Transactionable(Box::new(transaction)),
361 signer,
362 tx_live_for: None,
363 }
364 }
365
366 pub fn from_box(transaction: Box<dyn Transactionable + 'static>, signer: Arc<Signer>) -> Self {
367 Self {
368 transaction: TransactionableOrSigned::Transactionable(transaction),
369 signer,
370 tx_live_for: None,
371 }
372 }
373
374 pub const fn tx_live_for(mut self, tx_live_for: BlockHeight) -> Self {
379 self.tx_live_for = Some(tx_live_for);
380 self
381 }
382
383 pub async fn presign_offline(
391 mut self,
392 signer_key: PublicKey,
393 block_hash: CryptoHash,
394 nonce: Nonce,
395 block_height: BlockHeight,
396 ) -> Result<Self, ExecuteMetaTransactionsError> {
397 let transaction = match &self.transaction {
398 TransactionableOrSigned::Transactionable(transaction) => transaction,
399 TransactionableOrSigned::Signed(_) => return Ok(self),
400 };
401
402 let transaction = transaction.prepopulated()?;
403 let max_block_height = block_height
404 + self
405 .tx_live_for
406 .unwrap_or(META_TRANSACTION_VALID_FOR_DEFAULT);
407
408 let signed_tr = self
409 .signer
410 .sign_meta(transaction, signer_key, nonce, block_hash, max_block_height)
411 .await?;
412
413 self.transaction =
414 TransactionableOrSigned::Signed((signed_tr, self.transaction.transactionable()));
415 Ok(self)
416 }
417
418 pub async fn presign_with(
424 self,
425 network: &NetworkConfig,
426 ) -> Result<Self, ExecuteMetaTransactionsError> {
427 let transaction = match &self.transaction {
428 TransactionableOrSigned::Transactionable(transaction) => transaction,
429 TransactionableOrSigned::Signed(_) => return Ok(self),
430 };
431
432 let transaction = transaction.prepopulated()?;
433 let signer_key = self
434 .signer
435 .get_public_key()
436 .await
437 .map_err(SignerError::from)
438 .map_err(MetaSignError::from)?;
439 let (nonce, block_hash, block_height) = self
440 .signer
441 .fetch_tx_nonce(transaction.signer_id.clone(), signer_key, network)
442 .await
443 .map_err(MetaSignError::from)?;
444 self.presign_offline(signer_key, block_hash, nonce, block_height)
445 .await
446 }
447
448 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
454 let network = NetworkConfig::mainnet();
455 self.presign_with(&network).await
456 }
457
458 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
464 let network = NetworkConfig::testnet();
465 self.presign_with(&network).await
466 }
467
468 pub async fn send_to(
473 mut self,
474 network: &NetworkConfig,
475 ) -> Result<Response, ExecuteMetaTransactionsError> {
476 let (signed, transactionable) = match &mut self.transaction {
477 TransactionableOrSigned::Transactionable(transaction) => {
478 debug!(target: META_EXECUTOR_TARGET, "Preparing unsigned meta transaction");
479 (None, transaction)
480 }
481 TransactionableOrSigned::Signed((s, transaction)) => {
482 debug!(target: META_EXECUTOR_TARGET, "Using pre-signed meta transaction");
483 (Some(s.clone()), transaction)
484 }
485 };
486
487 if signed.is_none() {
488 debug!(target: META_EXECUTOR_TARGET, "Editing meta transaction with network config");
489 transactionable.edit_with_network(network).await?;
490 } else {
491 debug!(target: META_EXECUTOR_TARGET, "Validating pre-signed meta transaction with network config");
492 transactionable.validate_with_network(network).await?;
493 }
494
495 let signed = match signed {
496 Some(s) => s,
497 None => {
498 debug!(target: META_EXECUTOR_TARGET, "Signing meta transaction");
499 self.presign_with(network)
500 .await?
501 .transaction
502 .signed()
503 .expect("Expect to have it signed")
504 }
505 };
506
507 info!(
508 target: META_EXECUTOR_TARGET,
509 "Broadcasting signed meta transaction. Signer: {:?}, Receiver: {:?}, Nonce: {}, Valid until: {}",
510 signed.delegate_action.sender_id,
511 signed.delegate_action.receiver_id,
512 signed.delegate_action.nonce,
513 signed.delegate_action.max_block_height
514 );
515
516 Self::send_impl(network, signed).await
517 }
518
519 pub async fn send_to_mainnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
523 let network = NetworkConfig::mainnet();
524 self.send_to(&network).await
525 }
526
527 pub async fn send_to_testnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
531 let network = NetworkConfig::testnet();
532 self.send_to(&network).await
533 }
534
535 async fn send_impl(
536 network: &NetworkConfig,
537 transaction: SignedDelegateAction,
538 ) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
539 let client = reqwest::Client::new();
540 let json_payload = serde_json::json!({
541 "signed_delegate_action": SignedDelegateActionAsBase64::from(
542 transaction.clone()
543 ).to_string(),
544 });
545 debug!(
546 target: META_EXECUTOR_TARGET,
547 "Sending meta transaction to relayer. Payload: {:?}",
548 json_payload
549 );
550 let resp = client
551 .post(
552 network
553 .meta_transaction_relayer_url
554 .clone()
555 .ok_or(ExecuteMetaTransactionsError::RelayerIsNotDefined)?,
556 )
557 .json(&json_payload)
558 .send()
559 .await?;
560
561 info!(
562 target: META_EXECUTOR_TARGET,
563 "Meta transaction sent to relayer. Status: {}, Signer: {:?}, Receiver: {:?}",
564 resp.status(),
565 transaction.delegate_action.sender_id,
566 transaction.delegate_action.receiver_id
567 );
568 Ok(resp)
569 }
570}
571
572impl From<ErrorWrapperForRpcTransactionError> for SendRequestError<RpcTransactionError> {
573 fn from(err: ErrorWrapperForRpcTransactionError) -> Self {
574 match err {
575 ErrorWrapperForRpcTransactionError::InternalError(internal_error) => {
576 Self::InternalError(internal_error)
577 }
578 ErrorWrapperForRpcTransactionError::RequestValidationError(
579 rpc_request_validation_error_kind,
580 ) => Self::RequestValidationError(rpc_request_validation_error_kind),
581 ErrorWrapperForRpcTransactionError::HandlerError(server_error) => {
582 Self::ServerError(server_error)
583 }
584 }
585 }
586}