near_api/transactions.rs
1use std::sync::Arc;
2
3use near_api_types::{transaction::PrepopulateTransaction, AccountId, Action};
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}