near_api_types/transaction/
mod.rs1use std::{io::Write, str::FromStr, sync::OnceLock};
2
3pub mod actions;
4pub mod delegate_action;
5pub mod result;
6
7use base64::{Engine, prelude::BASE64_STANDARD};
8use borsh::{BorshDeserialize, BorshSerialize};
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 AccountId, Action, CryptoHash, Nonce, PublicKey, Signature, errors::DataConversionError,
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 #[allow(clippy::expect_used)]
95 let bytes = borsh::to_vec(&self).expect("Failed to serialize");
96 CryptoHash::hash(&bytes)
97 }
98}
99
100impl BorshSerialize for Transaction {
101 fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
102 match self {
103 Self::V0(tx) => BorshSerialize::serialize(tx, writer)?,
104 Self::V1(tx) => {
105 BorshSerialize::serialize(&1_u8, writer)?;
106 BorshSerialize::serialize(tx, writer)?;
107 }
108 }
109 Ok(())
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
114pub struct SignedTransaction {
115 pub transaction: Transaction,
116 pub signature: Signature,
117 #[borsh(skip)]
118 #[serde(skip)]
119 hash: OnceLock<CryptoHash>,
120}
121
122impl TryFrom<near_openapi_types::SignedTransactionView> for SignedTransaction {
123 type Error = DataConversionError;
124
125 fn try_from(value: near_openapi_types::SignedTransactionView) -> Result<Self, Self::Error> {
126 let near_openapi_types::SignedTransactionView {
127 signer_id,
128 public_key,
129 nonce,
130 receiver_id,
131 actions,
132 priority_fee,
133 hash,
134 signature,
135 } = value;
136
137 let transaction = if priority_fee > 0 {
138 Transaction::V1(TransactionV1 {
139 signer_id,
140 public_key: public_key.try_into()?,
141 nonce,
142 receiver_id,
143 block_hash: hash.into(),
144 actions: actions
145 .into_iter()
146 .map(Action::try_from)
147 .collect::<Result<Vec<_>, _>>()?,
148 priority_fee,
149 })
150 } else {
151 Transaction::V0(TransactionV0 {
152 signer_id,
153 public_key: public_key.try_into()?,
154 nonce,
155 receiver_id,
156 block_hash: hash.into(),
157 actions: actions
158 .into_iter()
159 .map(Action::try_from)
160 .collect::<Result<Vec<_>, _>>()?,
161 })
162 };
163
164 Ok(Self::new(Signature::from_str(&signature)?, transaction))
165 }
166}
167
168impl From<SignedTransaction> for near_openapi_types::SignedTransaction {
169 fn from(transaction: SignedTransaction) -> Self {
170 #[allow(clippy::expect_used)]
171 let bytes = borsh::to_vec(&transaction).expect("Failed to serialize");
172 Self(BASE64_STANDARD.encode(bytes))
173 }
174}
175
176impl From<SignedTransaction> for PrepopulateTransaction {
177 fn from(mut transaction: SignedTransaction) -> Self {
178 Self {
179 signer_id: transaction.transaction.signer_id().clone(),
180 receiver_id: transaction.transaction.receiver_id().clone(),
181 actions: transaction.transaction.take_actions(),
182 }
183 }
184}
185
186impl SignedTransaction {
187 pub const fn new(signature: Signature, transaction: Transaction) -> Self {
188 Self {
189 signature,
190 transaction,
191 hash: OnceLock::new(),
192 }
193 }
194
195 pub fn get_hash(&self) -> CryptoHash {
196 *self.hash.get_or_init(|| self.transaction.get_hash())
197 }
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
202pub struct PrepopulateTransaction {
203 pub signer_id: near_account_id::AccountId,
205 pub receiver_id: near_account_id::AccountId,
207 pub actions: Vec<Action>,
209}