near_api_types/transaction/
mod.rs

1use std::{io::Write, str::FromStr, sync::OnceLock};
2
3pub mod actions;
4pub mod delegate_action;
5pub mod result;
6
7use base64::{prelude::BASE64_STANDARD, Engine};
8use borsh::{BorshDeserialize, BorshSerialize};
9use serde::{Deserialize, Serialize};
10
11use crate::{
12    errors::DataConversionError, AccountId, Action, CryptoHash, Nonce, PublicKey, Signature,
13};
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
16pub struct TransactionV0 {
17    pub signer_id: AccountId,
18    pub public_key: PublicKey,
19    pub nonce: Nonce,
20    pub receiver_id: AccountId,
21    pub block_hash: CryptoHash,
22    pub actions: Vec<Action>,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
26pub struct TransactionV1 {
27    pub signer_id: AccountId,
28    pub public_key: PublicKey,
29    pub nonce: Nonce,
30    pub receiver_id: AccountId,
31    pub block_hash: CryptoHash,
32    pub actions: Vec<Action>,
33    pub priority_fee: u64,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
37pub enum Transaction {
38    V0(TransactionV0),
39    V1(TransactionV1),
40}
41
42impl Transaction {
43    pub const fn signer_id(&self) -> &AccountId {
44        match self {
45            Self::V0(tx) => &tx.signer_id,
46            Self::V1(tx) => &tx.signer_id,
47        }
48    }
49
50    pub const fn receiver_id(&self) -> &AccountId {
51        match self {
52            Self::V0(tx) => &tx.receiver_id,
53            Self::V1(tx) => &tx.receiver_id,
54        }
55    }
56
57    pub const fn nonce(&self) -> Nonce {
58        match self {
59            Self::V0(tx) => tx.nonce,
60            Self::V1(tx) => tx.nonce,
61        }
62    }
63
64    pub const fn public_key(&self) -> &PublicKey {
65        match self {
66            Self::V0(tx) => &tx.public_key,
67            Self::V1(tx) => &tx.public_key,
68        }
69    }
70
71    pub fn actions(&self) -> &[Action] {
72        match self {
73            Self::V0(tx) => &tx.actions,
74            Self::V1(tx) => &tx.actions,
75        }
76    }
77
78    pub const fn actions_mut(&mut self) -> &mut Vec<Action> {
79        match self {
80            Self::V0(tx) => &mut tx.actions,
81            Self::V1(tx) => &mut tx.actions,
82        }
83    }
84
85    pub fn take_actions(&mut self) -> Vec<Action> {
86        let actions = match self {
87            Self::V0(tx) => &mut tx.actions,
88            Self::V1(tx) => &mut tx.actions,
89        };
90        std::mem::take(actions)
91    }
92
93    pub fn get_hash(&self) -> CryptoHash {
94        let bytes = borsh::to_vec(&self).expect("Failed to deserialize");
95        CryptoHash::hash(&bytes)
96    }
97}
98
99impl BorshSerialize for Transaction {
100    fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
101        match self {
102            Self::V0(tx) => BorshSerialize::serialize(tx, writer)?,
103            Self::V1(tx) => {
104                BorshSerialize::serialize(&1_u8, writer)?;
105                BorshSerialize::serialize(tx, writer)?;
106            }
107        }
108        Ok(())
109    }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
113pub struct SignedTransaction {
114    pub transaction: Transaction,
115    pub signature: Signature,
116    #[borsh(skip)]
117    #[serde(skip)]
118    hash: OnceLock<CryptoHash>,
119}
120
121impl TryFrom<near_openapi_types::SignedTransactionView> for SignedTransaction {
122    type Error = DataConversionError;
123
124    fn try_from(value: near_openapi_types::SignedTransactionView) -> Result<Self, Self::Error> {
125        let near_openapi_types::SignedTransactionView {
126            signer_id,
127            public_key,
128            nonce,
129            receiver_id,
130            actions,
131            priority_fee,
132            hash,
133            signature,
134        } = value;
135
136        let transaction = if priority_fee > 0 {
137            Transaction::V1(TransactionV1 {
138                signer_id,
139                public_key: public_key.try_into()?,
140                nonce,
141                receiver_id,
142                block_hash: hash.try_into()?,
143                actions: actions
144                    .into_iter()
145                    .map(Action::try_from)
146                    .collect::<Result<Vec<_>, _>>()?,
147                priority_fee,
148            })
149        } else {
150            Transaction::V0(TransactionV0 {
151                signer_id,
152                public_key: public_key.try_into()?,
153                nonce,
154                receiver_id,
155                block_hash: hash.try_into()?,
156                actions: actions
157                    .into_iter()
158                    .map(Action::try_from)
159                    .collect::<Result<Vec<_>, _>>()?,
160            })
161        };
162
163        Ok(Self::new(Signature::from_str(&signature)?, transaction))
164    }
165}
166
167impl From<SignedTransaction> for near_openapi_types::SignedTransaction {
168    fn from(tr: SignedTransaction) -> Self {
169        let bytes = borsh::to_vec(&tr).expect("Failed to serialize");
170        Self(BASE64_STANDARD.encode(bytes))
171    }
172}
173
174impl From<SignedTransaction> for PrepopulateTransaction {
175    fn from(mut tr: SignedTransaction) -> Self {
176        Self {
177            signer_id: tr.transaction.signer_id().clone(),
178            receiver_id: tr.transaction.receiver_id().clone(),
179            actions: tr.transaction.take_actions(),
180        }
181    }
182}
183
184impl SignedTransaction {
185    pub const fn new(signature: Signature, transaction: Transaction) -> Self {
186        Self {
187            signature,
188            transaction,
189            hash: OnceLock::new(),
190        }
191    }
192
193    pub fn get_hash(&self) -> CryptoHash {
194        *self.hash.get_or_init(|| self.transaction.get_hash())
195    }
196}
197
198/// An internal type that represents unsigned transaction.
199#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
200pub struct PrepopulateTransaction {
201    /// The account that will sign the transaction.
202    pub signer_id: near_account_id::AccountId,
203    /// The account that will receive the transaction
204    pub receiver_id: near_account_id::AccountId,
205    /// The actions that will be executed by the transaction.
206    pub actions: Vec<Action>,
207}