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::{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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
200pub struct PrepopulateTransaction {
201 pub signer_id: near_account_id::AccountId,
203 pub receiver_id: near_account_id::AccountId,
205 pub actions: Vec<Action>,
207}