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: _, 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}