near_api_types/
account.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use serde::{Deserialize, Serialize};
3
4use crate::{errors::DataConversionError, AccountId, CryptoHash, NearToken, StorageUsage};
5
6#[derive(
7    Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq, Default,
8)]
9pub enum ContractState {
10    GlobalHash(CryptoHash),
11    GlobalAccountId(AccountId),
12    LocalHash(CryptoHash),
13    #[default]
14    None,
15}
16
17impl ContractState {
18    pub const fn from_global_contract_hash(hash: CryptoHash) -> Self {
19        Self::GlobalHash(hash)
20    }
21
22    pub const fn from_local_hash(hash: CryptoHash) -> Self {
23        Self::LocalHash(hash)
24    }
25}
26
27impl From<AccountId> for ContractState {
28    fn from(value: AccountId) -> Self {
29        Self::GlobalAccountId(value)
30    }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct Account {
35    pub amount: NearToken,
36    pub contract_state: ContractState,
37    pub locked: NearToken,
38    pub storage_usage: StorageUsage,
39}
40
41impl TryFrom<near_openapi_types::AccountView> for Account {
42    type Error = DataConversionError;
43
44    fn try_from(value: near_openapi_types::AccountView) -> Result<Self, Self::Error> {
45        let near_openapi_types::AccountView {
46            amount,
47            code_hash,
48            global_contract_account_id,
49            global_contract_hash,
50            locked,
51            storage_paid_at: _, // Intentionally ignoring this field. See (https://github.com/near/nearcore/issues/2271)
52            storage_usage,
53        } = value;
54
55        let code_hash = CryptoHash::try_from(code_hash)?;
56
57        let contract_state = match (code_hash, global_contract_account_id, global_contract_hash) {
58            (_, _, Some(hash)) => ContractState::from_global_contract_hash(hash.try_into()?),
59            (_, Some(account_id), _) => account_id.into(),
60            (hash, _, _) if hash == CryptoHash::default() => ContractState::None,
61            (hash, _, _) => ContractState::from_local_hash(hash),
62        };
63
64        Ok(Self {
65            amount,
66            contract_state,
67            locked,
68            storage_usage,
69        })
70    }
71}
72
73impl serde::Serialize for Account {
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde::Serializer,
77    {
78        let version = AccountVersion::V2;
79        let code_hash = match self.contract_state {
80            ContractState::LocalHash(hash) => hash,
81            _ => CryptoHash::default(),
82        };
83        let repr = SerdeAccount {
84            amount: self.amount,
85            locked: self.locked,
86            code_hash,
87            storage_usage: self.storage_usage,
88            version,
89            global_contract_hash: match &self.contract_state {
90                ContractState::GlobalHash(hash) => Some(*hash),
91                _ => None,
92            },
93            global_contract_account_id: match &self.contract_state {
94                ContractState::GlobalAccountId(account_id) => Some(account_id.clone()),
95                _ => None,
96            },
97        };
98        serde::Serialize::serialize(&repr, serializer)
99    }
100}
101
102#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
103pub enum AccountVersion {
104    V1,
105    V2,
106}
107
108#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
109pub struct SerdeAccount {
110    pub amount: NearToken,
111    pub locked: NearToken,
112    pub code_hash: CryptoHash,
113    pub storage_usage: u64,
114    pub version: AccountVersion,
115    pub global_contract_hash: Option<CryptoHash>,
116    pub global_contract_account_id: Option<AccountId>,
117}