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 ExecuteMetaTransactionsError, ExecuteTransactionError, MetaSignError, SendRequestError,
25 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) -> PrepopulateTransaction;
38 async fn validate_with_network(&self, network: &NetworkConfig) -> Result<(), ValidationError>;
40
41 async fn edit_with_network(&mut self, _network: &NetworkConfig) -> Result<(), ValidationError> {
46 Ok(())
47 }
48}
49
50pub enum TransactionableOrSigned<Signed> {
51 Transactionable(Box<dyn Transactionable + 'static>),
53 Signed((Signed, Box<dyn Transactionable + 'static>)),
55}
56
57impl<Signed> TransactionableOrSigned<Signed> {
58 pub fn signed(self) -> Option<Signed> {
59 match self {
60 Self::Signed((signed, _)) => Some(signed),
61 Self::Transactionable(_) => None,
62 }
63 }
64}
65
66impl<S> TransactionableOrSigned<S> {
67 pub fn transactionable(self) -> Box<dyn Transactionable> {
68 match self {
69 Self::Transactionable(tr) => tr,
70 Self::Signed((_, tr)) => tr,
71 }
72 }
73}
74
75pub struct ExecuteSignedTransaction {
79 pub tr: TransactionableOrSigned<SignedTransaction>,
81 pub signer: Arc<Signer>,
83
84 pub wait_until: TxExecutionStatus,
85}
86
87impl ExecuteSignedTransaction {
88 pub fn new<T: Transactionable + 'static>(tr: T, signer: Arc<Signer>) -> Self {
89 Self {
90 tr: TransactionableOrSigned::Transactionable(Box::new(tr)),
91 signer,
92 wait_until: TxExecutionStatus::Final,
93 }
94 }
95
96 pub fn meta(self) -> ExecuteMetaTransaction {
102 ExecuteMetaTransaction::from_box(self.tr.transactionable(), self.signer)
103 }
104
105 pub const fn wait_until(mut self, wait_until: TxExecutionStatus) -> Self {
106 self.wait_until = wait_until;
107 self
108 }
109
110 pub async fn presign_offline(
117 mut self,
118 public_key: PublicKey,
119 block_hash: CryptoHash,
120 nonce: Nonce,
121 ) -> Result<Self, SignerError> {
122 let tr = match &self.tr {
123 TransactionableOrSigned::Transactionable(tr) => tr,
124 TransactionableOrSigned::Signed(_) => return Ok(self),
125 };
126
127 let signed_tr = self
128 .signer
129 .sign(tr.prepopulated(), public_key.clone(), nonce, block_hash)
130 .await?;
131
132 self.tr = TransactionableOrSigned::Signed((signed_tr, self.tr.transactionable()));
133 Ok(self)
134 }
135
136 pub async fn presign_with(
143 self,
144 network: &NetworkConfig,
145 ) -> Result<Self, ExecuteTransactionError> {
146 let tr = match &self.tr {
147 TransactionableOrSigned::Transactionable(tr) => tr,
148 TransactionableOrSigned::Signed(_) => return Ok(self),
149 };
150
151 let signer_key = self.signer.get_public_key().await?;
152 let tr = tr.prepopulated();
153 let (nonce, hash, _) = self
154 .signer
155 .fetch_tx_nonce(tr.signer_id.clone(), signer_key.clone(), network)
156 .await
157 .map_err(MetaSignError::from)?;
158 Ok(self.presign_offline(signer_key, hash, nonce).await?)
159 }
160
161 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteTransactionError> {
167 let network = NetworkConfig::mainnet();
168 self.presign_with(&network).await
169 }
170
171 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteTransactionError> {
177 let network = NetworkConfig::testnet();
178 self.presign_with(&network).await
179 }
180
181 pub async fn send_to(
186 mut self,
187 network: &NetworkConfig,
188 ) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
189 let (signed, transactionable) = match &mut self.tr {
190 TransactionableOrSigned::Transactionable(tr) => {
191 debug!(target: TX_EXECUTOR_TARGET, "Preparing unsigned transaction");
192 (None, tr)
193 }
194 TransactionableOrSigned::Signed((s, tr)) => {
195 debug!(target: TX_EXECUTOR_TARGET, "Using pre-signed transaction");
196 (Some(s.clone()), tr)
197 }
198 };
199
200 let wait_until = self.wait_until;
201
202 if signed.is_none() {
203 debug!(target: TX_EXECUTOR_TARGET, "Editing transaction with network config");
204 transactionable.edit_with_network(network).await?;
205 } else {
206 debug!(target: TX_EXECUTOR_TARGET, "Validating pre-signed transaction with network config");
207 transactionable.validate_with_network(network).await?;
208 }
209
210 let signed = match signed {
211 Some(s) => s,
212 None => {
213 debug!(target: TX_EXECUTOR_TARGET, "Signing transaction");
214 self.presign_with(network)
215 .await?
216 .tr
217 .signed()
218 .expect("Expect to have it signed")
219 }
220 };
221
222 info!(
223 target: TX_EXECUTOR_TARGET,
224 "Broadcasting signed transaction. Hash: {:?}, Signer: {:?}, Receiver: {:?}, Nonce: {}",
225 signed.get_hash(),
226 signed.transaction.signer_id(),
227 signed.transaction.receiver_id(),
228 signed.transaction.nonce(),
229 );
230
231 Self::send_impl(network, signed, wait_until).await
232 }
233
234 pub async fn send_to_mainnet(self) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
238 let network = NetworkConfig::mainnet();
239 self.send_to(&network).await
240 }
241
242 pub async fn send_to_testnet(self) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
246 let network = NetworkConfig::testnet();
247 self.send_to(&network).await
248 }
249
250 async fn send_impl(
251 network: &NetworkConfig,
252 signed_tr: SignedTransaction,
253 wait_until: TxExecutionStatus,
254 ) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
255 let hash = signed_tr.get_hash();
256 let signed_tx_base64: near_openapi_client::types::SignedTransaction = signed_tr.into();
257 let result = retry(network.clone(), |client| {
258 let signed_tx_base64 = signed_tx_base64.clone();
259 async move {
260 let result = match client
261 .send_tx(&JsonRpcRequestForSendTx {
262 id: "0".to_string(),
263 jsonrpc: "2.0".to_string(),
264 method: near_openapi_client::types::JsonRpcRequestForSendTxMethod::SendTx,
265 params: RpcSendTransactionRequest {
266 signed_tx_base64,
267 wait_until,
268 },
269 })
270 .await
271 .map(|r| r.into_inner())
272 .map_err(SendRequestError::from)
273 {
274 Ok(
275 JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant0 {
276 result,
277 ..
278 },
279 ) => RetryResponse::Ok(result),
280 Ok(
281 JsonRpcResponseForRpcTransactionResponseAndRpcTransactionError::Variant1 {
282 error,
283 ..
284 },
285 ) => {
286 let error: SendRequestError<RpcTransactionError> =
287 SendRequestError::from(error);
288 to_retry_error(error, is_critical_transaction_error)
289 }
290 Err(err) => to_retry_error(err, is_critical_transaction_error),
291 };
292
293 tracing::debug!(
294 target: TX_EXECUTOR_TARGET,
295 "Broadcasting transaction {} resulted in {:?}",
296 hash,
297 result
298 );
299
300 result
301 }
302 })
303 .await
304 .map_err(ExecuteTransactionError::TransactionError)?;
305
306 let final_execution_outcome_view = match result {
308 RpcTransactionResponse::Variant0 {
310 final_execution_status: _,
311 receipts: _,
312 receipts_outcome,
313 status,
314 transaction,
315 transaction_outcome,
316 } => FinalExecutionOutcomeView {
317 receipts_outcome,
318 status,
319 transaction,
320 transaction_outcome,
321 },
322 RpcTransactionResponse::Variant1 {
323 final_execution_status: _,
324 receipts_outcome,
325 status,
326 transaction,
327 transaction_outcome,
328 } => FinalExecutionOutcomeView {
329 receipts_outcome,
330 status,
331 transaction,
332 transaction_outcome,
333 },
334 };
335
336 Ok(ExecutionFinalResult::try_from(
337 final_execution_outcome_view,
338 )?)
339 }
340}
341
342pub struct ExecuteMetaTransaction {
343 pub tr: TransactionableOrSigned<SignedDelegateAction>,
344 pub signer: Arc<Signer>,
345 pub tx_live_for: Option<BlockHeight>,
346}
347
348impl ExecuteMetaTransaction {
349 pub fn new<T: Transactionable + 'static>(tr: T, signer: Arc<Signer>) -> Self {
350 Self {
351 tr: TransactionableOrSigned::Transactionable(Box::new(tr)),
352 signer,
353 tx_live_for: None,
354 }
355 }
356
357 pub fn from_box(tr: Box<dyn Transactionable + 'static>, signer: Arc<Signer>) -> Self {
358 Self {
359 tr: TransactionableOrSigned::Transactionable(tr),
360 signer,
361 tx_live_for: None,
362 }
363 }
364
365 pub const fn tx_live_for(mut self, tx_live_for: BlockHeight) -> Self {
370 self.tx_live_for = Some(tx_live_for);
371 self
372 }
373
374 pub async fn presign_offline(
382 mut self,
383 signer_key: PublicKey,
384 block_hash: CryptoHash,
385 nonce: Nonce,
386 block_height: BlockHeight,
387 ) -> Result<Self, ExecuteMetaTransactionsError> {
388 let tr = match &self.tr {
389 TransactionableOrSigned::Transactionable(tr) => tr,
390 TransactionableOrSigned::Signed(_) => return Ok(self),
391 };
392
393 let max_block_height = block_height
394 + self
395 .tx_live_for
396 .unwrap_or(META_TRANSACTION_VALID_FOR_DEFAULT);
397
398 let signed_tr = self
399 .signer
400 .sign_meta(
401 tr.prepopulated(),
402 signer_key,
403 nonce,
404 block_hash,
405 max_block_height,
406 )
407 .await?;
408
409 self.tr = TransactionableOrSigned::Signed((signed_tr, self.tr.transactionable()));
410 Ok(self)
411 }
412
413 pub async fn presign_with(
419 self,
420 network: &NetworkConfig,
421 ) -> Result<Self, ExecuteMetaTransactionsError> {
422 let tr = match &self.tr {
423 TransactionableOrSigned::Transactionable(tr) => tr,
424 TransactionableOrSigned::Signed(_) => return Ok(self),
425 };
426
427 let signer_key = self
428 .signer
429 .get_public_key()
430 .await
431 .map_err(MetaSignError::from)?;
432 let (nonce, block_hash, block_height) = self
433 .signer
434 .fetch_tx_nonce(
435 tr.prepopulated().signer_id.clone(),
436 signer_key.clone(),
437 network,
438 )
439 .await
440 .map_err(MetaSignError::from)?;
441 self.presign_offline(signer_key, block_hash, nonce, block_height)
442 .await
443 }
444
445 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
451 let network = NetworkConfig::mainnet();
452 self.presign_with(&network).await
453 }
454
455 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
461 let network = NetworkConfig::testnet();
462 self.presign_with(&network).await
463 }
464
465 pub async fn send_to(
470 mut self,
471 network: &NetworkConfig,
472 ) -> Result<Response, ExecuteMetaTransactionsError> {
473 let (signed, transactionable) = match &mut self.tr {
474 TransactionableOrSigned::Transactionable(tr) => {
475 debug!(target: META_EXECUTOR_TARGET, "Preparing unsigned meta transaction");
476 (None, tr)
477 }
478 TransactionableOrSigned::Signed((s, tr)) => {
479 debug!(target: META_EXECUTOR_TARGET, "Using pre-signed meta transaction");
480 (Some(s.clone()), tr)
481 }
482 };
483
484 if signed.is_none() {
485 debug!(target: META_EXECUTOR_TARGET, "Editing meta transaction with network config");
486 transactionable.edit_with_network(network).await?;
487 } else {
488 debug!(target: META_EXECUTOR_TARGET, "Validating pre-signed meta transaction with network config");
489 transactionable.validate_with_network(network).await?;
490 }
491
492 let signed = match signed {
493 Some(s) => s,
494 None => {
495 debug!(target: META_EXECUTOR_TARGET, "Signing meta transaction");
496 self.presign_with(network)
497 .await?
498 .tr
499 .signed()
500 .expect("Expect to have it signed")
501 }
502 };
503
504 info!(
505 target: META_EXECUTOR_TARGET,
506 "Broadcasting signed meta transaction. Signer: {:?}, Receiver: {:?}, Nonce: {}, Valid until: {}",
507 signed.delegate_action.sender_id,
508 signed.delegate_action.receiver_id,
509 signed.delegate_action.nonce,
510 signed.delegate_action.max_block_height
511 );
512
513 Self::send_impl(network, signed).await
514 }
515
516 pub async fn send_to_mainnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
520 let network = NetworkConfig::mainnet();
521 self.send_to(&network).await
522 }
523
524 pub async fn send_to_testnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
528 let network = NetworkConfig::testnet();
529 self.send_to(&network).await
530 }
531
532 async fn send_impl(
533 network: &NetworkConfig,
534 tr: SignedDelegateAction,
535 ) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
536 let client = reqwest::Client::new();
537 let json_payload = serde_json::json!({
538 "signed_delegate_action": SignedDelegateActionAsBase64::from(
539 tr.clone()
540 ).to_string(),
541 });
542 debug!(
543 target: META_EXECUTOR_TARGET,
544 "Sending meta transaction to relayer. Payload: {:?}",
545 json_payload
546 );
547 let resp = client
548 .post(
549 network
550 .meta_transaction_relayer_url
551 .clone()
552 .ok_or(ExecuteMetaTransactionsError::RelayerIsNotDefined)?,
553 )
554 .json(&json_payload)
555 .send()
556 .await?;
557
558 info!(
559 target: META_EXECUTOR_TARGET,
560 "Meta transaction sent to relayer. Status: {}, Signer: {:?}, Receiver: {:?}",
561 resp.status(),
562 tr.delegate_action.sender_id,
563 tr.delegate_action.receiver_id
564 );
565 Ok(resp)
566 }
567}
568
569impl From<ErrorWrapperForRpcTransactionError> for SendRequestError<RpcTransactionError> {
570 fn from(err: ErrorWrapperForRpcTransactionError) -> Self {
571 match err {
572 ErrorWrapperForRpcTransactionError::InternalError(internal_error) => {
573 Self::InternalError(internal_error)
574 }
575 ErrorWrapperForRpcTransactionError::RequestValidationError(
576 rpc_request_validation_error_kind,
577 ) => Self::RequestValidationError(rpc_request_validation_error_kind),
578 ErrorWrapperForRpcTransactionError::HandlerError(server_error) => {
579 Self::ServerError(server_error)
580 }
581 }
582 }
583}