1use std::sync::Arc;
2
3use near_openapi_client::types::{
4 FinalExecutionOutcomeView, JsonRpcRequestForSendTx,
5 JsonRpcResponseForRpcTransactionResponseAndRpcError, RpcSendTransactionRequest,
6 RpcTransactionResponse,
7};
8
9use near_api_types::{
10 BlockHeight, CryptoHash, Nonce, PublicKey, TxExecutionStatus,
11 transaction::{
12 PrepopulateTransaction, SignedTransaction,
13 delegate_action::{SignedDelegateAction, SignedDelegateActionAsBase64},
14 result::ExecutionFinalResult,
15 },
16};
17use reqwest::Response;
18use tracing::{debug, info};
19
20use crate::{
21 common::utils::is_critical_transaction_error,
22 config::{NetworkConfig, RetryResponse, retry},
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 {
272 Ok(result) => match result.into_inner() {
273 JsonRpcResponseForRpcTransactionResponseAndRpcError::Variant0 {
274 result,
275 ..
276 } => RetryResponse::Ok(result),
277 JsonRpcResponseForRpcTransactionResponseAndRpcError::Variant1 {
278 error,
279 ..
280 } => {
281 if is_critical_transaction_error(&error) {
282 RetryResponse::Critical(SendRequestError::ServerError(error))
283 } else {
284 RetryResponse::Retry(SendRequestError::ServerError(error))
285 }
286 }
287 },
288 Err(err) => RetryResponse::Critical(SendRequestError::ClientError(err)),
289 };
290
291 tracing::debug!(
292 target: TX_EXECUTOR_TARGET,
293 "Broadcasting transaction {} resulted in {:?}",
294 hash,
295 result
296 );
297
298 result
299 }
300 })
301 .await
302 .map_err(ExecuteTransactionError::TransactionError)?;
303
304 let final_execution_outcome_view = match result {
306 RpcTransactionResponse::Variant0 {
308 final_execution_status: _,
309 receipts: _,
310 receipts_outcome,
311 status,
312 transaction,
313 transaction_outcome,
314 } => FinalExecutionOutcomeView {
315 receipts_outcome,
316 status,
317 transaction,
318 transaction_outcome,
319 },
320 RpcTransactionResponse::Variant1 {
321 final_execution_status: _,
322 receipts_outcome,
323 status,
324 transaction,
325 transaction_outcome,
326 } => FinalExecutionOutcomeView {
327 receipts_outcome,
328 status,
329 transaction,
330 transaction_outcome,
331 },
332 };
333
334 Ok(ExecutionFinalResult::try_from(
335 final_execution_outcome_view,
336 )?)
337 }
338}
339
340pub struct ExecuteMetaTransaction {
341 pub tr: TransactionableOrSigned<SignedDelegateAction>,
342 pub signer: Arc<Signer>,
343 pub tx_live_for: Option<BlockHeight>,
344}
345
346impl ExecuteMetaTransaction {
347 pub fn new<T: Transactionable + 'static>(tr: T, signer: Arc<Signer>) -> Self {
348 Self {
349 tr: TransactionableOrSigned::Transactionable(Box::new(tr)),
350 signer,
351 tx_live_for: None,
352 }
353 }
354
355 pub fn from_box(tr: Box<dyn Transactionable + 'static>, signer: Arc<Signer>) -> Self {
356 Self {
357 tr: TransactionableOrSigned::Transactionable(tr),
358 signer,
359 tx_live_for: None,
360 }
361 }
362
363 pub const fn tx_live_for(mut self, tx_live_for: BlockHeight) -> Self {
368 self.tx_live_for = Some(tx_live_for);
369 self
370 }
371
372 pub async fn presign_offline(
380 mut self,
381 signer_key: PublicKey,
382 block_hash: CryptoHash,
383 nonce: Nonce,
384 block_height: BlockHeight,
385 ) -> Result<Self, ExecuteMetaTransactionsError> {
386 let tr = match &self.tr {
387 TransactionableOrSigned::Transactionable(tr) => tr,
388 TransactionableOrSigned::Signed(_) => return Ok(self),
389 };
390
391 let max_block_height = block_height
392 + self
393 .tx_live_for
394 .unwrap_or(META_TRANSACTION_VALID_FOR_DEFAULT);
395
396 let signed_tr = self
397 .signer
398 .sign_meta(
399 tr.prepopulated(),
400 signer_key,
401 nonce,
402 block_hash,
403 max_block_height,
404 )
405 .await?;
406
407 self.tr = TransactionableOrSigned::Signed((signed_tr, self.tr.transactionable()));
408 Ok(self)
409 }
410
411 pub async fn presign_with(
417 self,
418 network: &NetworkConfig,
419 ) -> Result<Self, ExecuteMetaTransactionsError> {
420 let tr = match &self.tr {
421 TransactionableOrSigned::Transactionable(tr) => tr,
422 TransactionableOrSigned::Signed(_) => return Ok(self),
423 };
424
425 let signer_key = self
426 .signer
427 .get_public_key()
428 .await
429 .map_err(MetaSignError::from)?;
430 let (nonce, block_hash, block_height) = self
431 .signer
432 .fetch_tx_nonce(
433 tr.prepopulated().signer_id.clone(),
434 signer_key.clone(),
435 network,
436 )
437 .await
438 .map_err(MetaSignError::from)?;
439 self.presign_offline(signer_key, block_hash, nonce, block_height)
440 .await
441 }
442
443 pub async fn presign_with_mainnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
449 let network = NetworkConfig::mainnet();
450 self.presign_with(&network).await
451 }
452
453 pub async fn presign_with_testnet(self) -> Result<Self, ExecuteMetaTransactionsError> {
459 let network = NetworkConfig::testnet();
460 self.presign_with(&network).await
461 }
462
463 pub async fn send_to(
468 mut self,
469 network: &NetworkConfig,
470 ) -> Result<Response, ExecuteMetaTransactionsError> {
471 let (signed, transactionable) = match &mut self.tr {
472 TransactionableOrSigned::Transactionable(tr) => {
473 debug!(target: META_EXECUTOR_TARGET, "Preparing unsigned meta transaction");
474 (None, tr)
475 }
476 TransactionableOrSigned::Signed((s, tr)) => {
477 debug!(target: META_EXECUTOR_TARGET, "Using pre-signed meta transaction");
478 (Some(s.clone()), tr)
479 }
480 };
481
482 if signed.is_none() {
483 debug!(target: META_EXECUTOR_TARGET, "Editing meta transaction with network config");
484 transactionable.edit_with_network(network).await?;
485 } else {
486 debug!(target: META_EXECUTOR_TARGET, "Validating pre-signed meta transaction with network config");
487 transactionable.validate_with_network(network).await?;
488 }
489
490 let signed = match signed {
491 Some(s) => s,
492 None => {
493 debug!(target: META_EXECUTOR_TARGET, "Signing meta transaction");
494 self.presign_with(network)
495 .await?
496 .tr
497 .signed()
498 .expect("Expect to have it signed")
499 }
500 };
501
502 info!(
503 target: META_EXECUTOR_TARGET,
504 "Broadcasting signed meta transaction. Signer: {:?}, Receiver: {:?}, Nonce: {}, Valid until: {}",
505 signed.delegate_action.sender_id,
506 signed.delegate_action.receiver_id,
507 signed.delegate_action.nonce,
508 signed.delegate_action.max_block_height
509 );
510
511 Self::send_impl(network, signed).await
512 }
513
514 pub async fn send_to_mainnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
518 let network = NetworkConfig::mainnet();
519 self.send_to(&network).await
520 }
521
522 pub async fn send_to_testnet(self) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
526 let network = NetworkConfig::testnet();
527 self.send_to(&network).await
528 }
529
530 async fn send_impl(
531 network: &NetworkConfig,
532 tr: SignedDelegateAction,
533 ) -> Result<reqwest::Response, ExecuteMetaTransactionsError> {
534 let client = reqwest::Client::new();
535 let json_payload = serde_json::json!({
536 "signed_delegate_action": SignedDelegateActionAsBase64::from(
537 tr.clone()
538 ).to_string(),
539 });
540 debug!(
541 target: META_EXECUTOR_TARGET,
542 "Sending meta transaction to relayer. Payload: {:?}",
543 json_payload
544 );
545 let resp = client
546 .post(
547 network
548 .meta_transaction_relayer_url
549 .clone()
550 .ok_or(ExecuteMetaTransactionsError::RelayerIsNotDefined)?,
551 )
552 .json(&json_payload)
553 .send()
554 .await?;
555
556 info!(
557 target: META_EXECUTOR_TARGET,
558 "Meta transaction sent to relayer. Status: {}, Signer: {:?}, Receiver: {:?}",
559 resp.status(),
560 tr.delegate_action.sender_id,
561 tr.delegate_action.receiver_id
562 );
563 Ok(resp)
564 }
565}