near_api/
transactions.rs

1use std::sync::Arc;
2
3use near_api_types::{AccountId, Action, transaction::PrepopulateTransaction};
4
5use crate::{
6    common::send::{ExecuteSignedTransaction, Transactionable},
7    config::NetworkConfig,
8    errors::ValidationError,
9    signer::Signer,
10};
11
12#[derive(Clone, Debug)]
13pub struct TransactionWithSign<T: Transactionable + 'static> {
14    pub tx: T,
15}
16
17impl<T: Transactionable> TransactionWithSign<T> {
18    pub fn with_signer(self, signer: Arc<Signer>) -> ExecuteSignedTransaction {
19        ExecuteSignedTransaction::new(self.tx, signer)
20    }
21}
22
23#[derive(Clone, Debug)]
24pub struct SelfActionBuilder {
25    pub actions: Vec<Action>,
26}
27
28impl Default for SelfActionBuilder {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl SelfActionBuilder {
35    pub const fn new() -> Self {
36        Self {
37            actions: Vec::new(),
38        }
39    }
40
41    /// Adds an action to the transaction.
42    pub fn add_action(mut self, action: Action) -> Self {
43        self.actions.push(action);
44        self
45    }
46
47    /// Adds multiple actions to the transaction.
48    pub fn add_actions(mut self, actions: Vec<Action>) -> Self {
49        self.actions.extend(actions);
50        self
51    }
52
53    /// Signs the transaction with the given account id and signer related to it.
54    pub fn with_signer(
55        self,
56        signer_account_id: AccountId,
57        signer: Arc<Signer>,
58    ) -> ExecuteSignedTransaction {
59        ConstructTransaction::new(signer_account_id.clone(), signer_account_id)
60            .add_actions(self.actions)
61            .with_signer(signer)
62    }
63}
64
65/// A builder for constructing transactions using Actions.
66#[derive(Debug, Clone)]
67pub struct ConstructTransaction {
68    pub tr: PrepopulateTransaction,
69}
70
71impl ConstructTransaction {
72    /// Pre-populates a transaction with the given signer and receiver IDs.
73    pub const fn new(signer_id: AccountId, receiver_id: AccountId) -> Self {
74        Self {
75            tr: PrepopulateTransaction {
76                signer_id,
77                receiver_id,
78                actions: Vec::new(),
79            },
80        }
81    }
82
83    /// Adds an action to the transaction.
84    pub fn add_action(mut self, action: Action) -> Self {
85        self.tr.actions.push(action);
86        self
87    }
88
89    /// Adds multiple actions to the transaction.
90    pub fn add_actions(mut self, actions: Vec<Action>) -> Self {
91        self.tr.actions.extend(actions);
92        self
93    }
94
95    /// Signs the transaction with the given signer.
96    pub fn with_signer(self, signer: Arc<Signer>) -> ExecuteSignedTransaction {
97        ExecuteSignedTransaction::new(self, signer)
98    }
99}
100
101#[async_trait::async_trait]
102impl Transactionable for ConstructTransaction {
103    fn prepopulated(&self) -> PrepopulateTransaction {
104        PrepopulateTransaction {
105            signer_id: self.tr.signer_id.clone(),
106            receiver_id: self.tr.receiver_id.clone(),
107            actions: self.tr.actions.clone(),
108        }
109    }
110
111    async fn validate_with_network(&self, _: &NetworkConfig) -> Result<(), ValidationError> {
112        Ok(())
113    }
114}
115
116/// Transaction related functionality.
117///
118/// This struct provides ability to interact with transactions.
119#[derive(Clone, Debug)]
120pub struct Transaction;
121
122impl Transaction {
123    /// Constructs a new transaction builder with the given signer and receiver IDs.
124    /// This pattern is useful for batching actions into a single transaction.
125    ///
126    /// This is the low level interface for constructing transactions.
127    /// It is designed to be used in scenarios where more control over the transaction process is required.
128    ///
129    /// # Example
130    ///
131    /// This example constructs a transaction with a two transfer actions.
132    ///
133    /// ```rust,no_run
134    /// use near_api::{*, types::{transaction::actions::{Action, TransferAction}, json::U128}};
135    ///
136    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
137    /// let signer = Signer::new(Signer::from_ledger())?;
138    ///
139    /// let transaction_result = Transaction::construct(
140    ///     "sender.near".parse()?,
141    ///     "receiver.near".parse()?
142    /// )
143    /// .add_action(Action::Transfer(
144    ///     TransferAction {
145    ///         deposit: NearToken::from_near(1),
146    ///     },
147    /// ))
148    /// .add_action(Action::Transfer(
149    ///     TransferAction {
150    ///         deposit: NearToken::from_near(1),
151    ///     },
152    /// ))
153    /// .with_signer(signer)
154    /// .send_to_mainnet()
155    /// .await?;
156    /// # Ok(())
157    /// # }
158    /// ```
159    pub const fn construct(signer_id: AccountId, receiver_id: AccountId) -> ConstructTransaction {
160        ConstructTransaction::new(signer_id, receiver_id)
161    }
162
163    /// Signs a transaction with the given signer.
164    ///
165    /// This provides ability to sign custom constructed pre-populated transactions.
166    ///
167    /// # Examples
168    ///
169    /// ```rust,no_run
170    /// use near_api::*;
171    ///
172    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
173    /// let signer = Signer::new(Signer::from_ledger())?;
174    /// # let unsigned_tx = todo!();
175    ///
176    /// let transaction_result = Transaction::use_transaction(
177    ///     unsigned_tx,
178    ///     signer
179    /// )
180    /// .send_to_mainnet()
181    /// .await?;
182    /// # Ok(())
183    /// # }
184    /// ```
185    pub fn use_transaction(
186        unsigned_tx: PrepopulateTransaction,
187        signer: Arc<Signer>,
188    ) -> ExecuteSignedTransaction {
189        ConstructTransaction::new(unsigned_tx.signer_id, unsigned_tx.receiver_id)
190            .add_actions(unsigned_tx.actions)
191            .with_signer(signer)
192    }
193
194    // TODO: fetch transaction status
195    // TODO: fetch transaction receipt
196    // TODO: fetch transaction proof
197}