near_primitives/action/
mod.rs

1pub mod delegate;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use near_crypto::PublicKey;
5use near_primitives_core::{
6    account::AccessKey,
7    hash::CryptoHash,
8    serialize::dec_format,
9    types::{AccountId, Balance, Gas},
10};
11use near_schema_checker_lib::ProtocolSchema;
12use serde_with::base64::Base64;
13use serde_with::serde_as;
14use std::fmt;
15use std::sync::Arc;
16
17use crate::trie_key::GlobalContractCodeIdentifier;
18
19pub fn base64(s: &[u8]) -> String {
20    use base64::Engine;
21    base64::engine::general_purpose::STANDARD.encode(s)
22}
23
24#[derive(
25    BorshSerialize,
26    BorshDeserialize,
27    PartialEq,
28    Eq,
29    Clone,
30    Debug,
31    serde::Serialize,
32    serde::Deserialize,
33    ProtocolSchema,
34)]
35#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
36pub struct AddKeyAction {
37    /// A public key which will be associated with an access_key
38    pub public_key: PublicKey,
39    /// An access key with the permission
40    pub access_key: AccessKey,
41}
42
43/// Create account action
44#[derive(
45    BorshSerialize,
46    BorshDeserialize,
47    PartialEq,
48    Eq,
49    Clone,
50    Debug,
51    serde::Serialize,
52    serde::Deserialize,
53    ProtocolSchema,
54)]
55#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
56pub struct CreateAccountAction {}
57
58#[derive(
59    BorshSerialize,
60    BorshDeserialize,
61    PartialEq,
62    Eq,
63    Clone,
64    Debug,
65    serde::Serialize,
66    serde::Deserialize,
67    ProtocolSchema,
68)]
69#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
70pub struct DeleteAccountAction {
71    pub beneficiary_id: AccountId,
72}
73
74#[derive(
75    BorshSerialize,
76    BorshDeserialize,
77    PartialEq,
78    Eq,
79    Clone,
80    Debug,
81    serde::Serialize,
82    serde::Deserialize,
83    ProtocolSchema,
84)]
85#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
86pub struct DeleteKeyAction {
87    /// A public key associated with the access_key to be deleted.
88    pub public_key: PublicKey,
89}
90
91/// Deploy contract action
92#[serde_as]
93#[derive(
94    BorshSerialize,
95    BorshDeserialize,
96    serde::Serialize,
97    serde::Deserialize,
98    PartialEq,
99    Eq,
100    Clone,
101    ProtocolSchema,
102)]
103#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
104pub struct DeployContractAction {
105    /// WebAssembly binary
106    #[serde_as(as = "Base64")]
107    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
108    pub code: Vec<u8>,
109}
110
111impl fmt::Debug for DeployContractAction {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.debug_struct("DeployContractAction")
114            .field("code", &format_args!("{}", base64(&self.code)))
115            .finish()
116    }
117}
118
119#[serde_as]
120#[derive(
121    BorshSerialize,
122    BorshDeserialize,
123    serde::Serialize,
124    serde::Deserialize,
125    PartialEq,
126    Eq,
127    Clone,
128    ProtocolSchema,
129    Debug,
130)]
131#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
132#[repr(u8)]
133pub enum GlobalContractDeployMode {
134    /// Contract is deployed under its code hash.
135    /// Users will be able reference it by that hash.
136    /// This effectively makes the contract immutable.
137    CodeHash,
138    /// Contract is deployed under the owner account id.
139    /// Users will be able reference it by that account id.
140    /// This allows the owner to update the contract for all its users.
141    AccountId,
142}
143
144/// Deploy global contract action
145#[serde_as]
146#[derive(
147    BorshSerialize,
148    BorshDeserialize,
149    serde::Serialize,
150    serde::Deserialize,
151    PartialEq,
152    Eq,
153    Clone,
154    ProtocolSchema,
155)]
156#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
157pub struct DeployGlobalContractAction {
158    /// WebAssembly binary
159    #[serde_as(as = "Base64")]
160    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
161    pub code: Arc<[u8]>,
162
163    pub deploy_mode: GlobalContractDeployMode,
164}
165
166impl fmt::Debug for DeployGlobalContractAction {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        f.debug_struct("DeployGlobalContractAction")
169            .field("code", &format_args!("{}", base64(&self.code)))
170            .field("deploy_mode", &format_args!("{:?}", &self.deploy_mode))
171            .finish()
172    }
173}
174
175#[serde_as]
176#[derive(
177    BorshSerialize,
178    BorshDeserialize,
179    serde::Serialize,
180    serde::Deserialize,
181    Hash,
182    PartialEq,
183    Eq,
184    Clone,
185    ProtocolSchema,
186    Debug,
187)]
188#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
189pub enum GlobalContractIdentifier {
190    CodeHash(CryptoHash),
191    AccountId(AccountId),
192}
193
194impl From<GlobalContractCodeIdentifier> for GlobalContractIdentifier {
195    fn from(identifier: GlobalContractCodeIdentifier) -> Self {
196        match identifier {
197            GlobalContractCodeIdentifier::CodeHash(hash) => {
198                GlobalContractIdentifier::CodeHash(hash)
199            }
200            GlobalContractCodeIdentifier::AccountId(account_id) => {
201                GlobalContractIdentifier::AccountId(account_id)
202            }
203        }
204    }
205}
206
207impl GlobalContractIdentifier {
208    pub fn len(&self) -> usize {
209        match self {
210            GlobalContractIdentifier::CodeHash(_) => 32,
211            GlobalContractIdentifier::AccountId(account_id) => account_id.len(),
212        }
213    }
214}
215
216/// Use global contract action
217#[serde_as]
218#[derive(
219    BorshSerialize,
220    BorshDeserialize,
221    serde::Serialize,
222    serde::Deserialize,
223    PartialEq,
224    Eq,
225    Clone,
226    ProtocolSchema,
227    Debug,
228)]
229#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
230pub struct UseGlobalContractAction {
231    pub contract_identifier: GlobalContractIdentifier,
232}
233
234#[serde_as]
235#[derive(
236    BorshSerialize,
237    BorshDeserialize,
238    serde::Serialize,
239    serde::Deserialize,
240    PartialEq,
241    Eq,
242    Clone,
243    ProtocolSchema,
244)]
245#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
246pub struct FunctionCallAction {
247    pub method_name: String,
248    #[serde_as(as = "Base64")]
249    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
250    pub args: Vec<u8>,
251    pub gas: Gas,
252    #[serde(with = "dec_format")]
253    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
254    pub deposit: Balance,
255}
256
257impl fmt::Debug for FunctionCallAction {
258    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259        f.debug_struct("FunctionCallAction")
260            .field("method_name", &format_args!("{}", &self.method_name))
261            .field("args", &format_args!("{}", base64(&self.args)))
262            .field("gas", &format_args!("{}", &self.gas))
263            .field("deposit", &format_args!("{}", &self.deposit))
264            .finish()
265    }
266}
267
268/// An action which stakes signer_id tokens and setup's validator public key
269#[derive(
270    BorshSerialize,
271    BorshDeserialize,
272    PartialEq,
273    Eq,
274    Clone,
275    Debug,
276    serde::Serialize,
277    serde::Deserialize,
278    ProtocolSchema,
279)]
280#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
281pub struct StakeAction {
282    /// Amount of tokens to stake.
283    #[serde(with = "dec_format")]
284    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
285    pub stake: Balance,
286    /// Validator key which will be used to sign transactions on behalf of signer_id
287    pub public_key: PublicKey,
288}
289
290#[derive(
291    BorshSerialize,
292    BorshDeserialize,
293    PartialEq,
294    Eq,
295    Clone,
296    Debug,
297    serde::Serialize,
298    serde::Deserialize,
299    ProtocolSchema,
300)]
301#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
302pub struct TransferAction {
303    #[serde(with = "dec_format")]
304    #[cfg_attr(feature = "schemars", schemars(with = "String"))]
305    pub deposit: Balance,
306}
307
308#[derive(
309    BorshSerialize,
310    BorshDeserialize,
311    PartialEq,
312    Eq,
313    Debug,
314    Clone,
315    serde::Serialize,
316    serde::Deserialize,
317    strum::AsRefStr,
318    ProtocolSchema,
319)]
320#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
321pub enum Action {
322    /// Create an (sub)account using a transaction `receiver_id` as an ID for
323    /// a new account ID must pass validation rules described here
324    /// <http://nomicon.io/Primitives/Account.html>.
325    CreateAccount(CreateAccountAction),
326    /// Sets a Wasm code to a receiver_id
327    DeployContract(DeployContractAction),
328    FunctionCall(Box<FunctionCallAction>),
329    Transfer(TransferAction),
330    Stake(Box<StakeAction>),
331    AddKey(Box<AddKeyAction>),
332    DeleteKey(Box<DeleteKeyAction>),
333    DeleteAccount(DeleteAccountAction),
334    Delegate(Box<delegate::SignedDelegateAction>),
335    DeployGlobalContract(DeployGlobalContractAction),
336    UseGlobalContract(Box<UseGlobalContractAction>),
337}
338
339const _: () = assert!(
340    // 1 word for tag plus the largest variant `DeployContractAction` which is a 3-word `Vec`.
341    // The `<=` check covers platforms that have pointers smaller than 8 bytes as well as random
342    // freak night lies that somehow find a way to pack everything into one less word.
343    std::mem::size_of::<Action>() <= 32,
344    "Action <= 32 bytes for performance reasons, see #9451"
345);
346
347impl Action {
348    pub fn get_prepaid_gas(&self) -> Gas {
349        match self {
350            Action::FunctionCall(a) => a.gas,
351            _ => 0,
352        }
353    }
354    pub fn get_deposit_balance(&self) -> Balance {
355        match self {
356            Action::FunctionCall(a) => a.deposit,
357            Action::Transfer(a) => a.deposit,
358            _ => 0,
359        }
360    }
361}
362
363impl From<CreateAccountAction> for Action {
364    fn from(create_account_action: CreateAccountAction) -> Self {
365        Self::CreateAccount(create_account_action)
366    }
367}
368
369impl From<DeployContractAction> for Action {
370    fn from(deploy_contract_action: DeployContractAction) -> Self {
371        Self::DeployContract(deploy_contract_action)
372    }
373}
374
375impl From<DeployGlobalContractAction> for Action {
376    fn from(deploy_global_contract_action: DeployGlobalContractAction) -> Self {
377        Self::DeployGlobalContract(deploy_global_contract_action)
378    }
379}
380
381impl From<FunctionCallAction> for Action {
382    fn from(function_call_action: FunctionCallAction) -> Self {
383        Self::FunctionCall(Box::new(function_call_action))
384    }
385}
386
387impl From<TransferAction> for Action {
388    fn from(transfer_action: TransferAction) -> Self {
389        Self::Transfer(transfer_action)
390    }
391}
392
393impl From<StakeAction> for Action {
394    fn from(stake_action: StakeAction) -> Self {
395        Self::Stake(Box::new(stake_action))
396    }
397}
398
399impl From<AddKeyAction> for Action {
400    fn from(add_key_action: AddKeyAction) -> Self {
401        Self::AddKey(Box::new(add_key_action))
402    }
403}
404
405impl From<DeleteKeyAction> for Action {
406    fn from(delete_key_action: DeleteKeyAction) -> Self {
407        Self::DeleteKey(Box::new(delete_key_action))
408    }
409}
410
411impl From<DeleteAccountAction> for Action {
412    fn from(delete_account_action: DeleteAccountAction) -> Self {
413        Self::DeleteAccount(delete_account_action)
414    }
415}