near_primitives/action/
mod.rs

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