defuse_core/engine/state/
mod.rs1pub mod cached;
2pub mod deltas;
3
4use crate::{
5 AccountId, AccountIdRef, Nonce, NoncePrefix, Result, Salt,
6 amounts::Amounts,
7 fees::Pips,
8 intents::{
9 auth::AuthCall,
10 tokens::{
11 FtWithdraw, MtWithdraw, NativeWithdraw, NftWithdraw, NotifyOnTransfer, StorageDeposit,
12 },
13 },
14 public_key::PublicKey,
15 token_id::{TokenId, nep141::Nep141TokenId},
16};
17use cached::CachedState;
18use impl_tools::autoimpl;
19use std::borrow::Cow;
20
21#[cfg(feature = "imt")]
22use crate::{
23 DefuseError,
24 tokens::{MT_ON_TRANSFER_GAS_DEFAULT, MT_ON_TRANSFER_GAS_MIN, imt::ImtTokens},
25};
26
27#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
28pub trait StateView {
29 fn verifying_contract(&self) -> Cow<'_, AccountIdRef>;
30 fn wnear_id(&self) -> Cow<'_, AccountIdRef>;
31 fn wnear_token_id(&self) -> TokenId {
32 Nep141TokenId::new(self.wnear_id().into_owned()).into()
33 }
34
35 fn fee(&self) -> Pips;
36 fn fee_collector(&self) -> Cow<'_, AccountIdRef>;
37
38 #[must_use]
39 fn has_public_key(&self, account_id: &AccountIdRef, public_key: &PublicKey) -> bool;
40 fn iter_public_keys(&self, account_id: &AccountIdRef) -> impl Iterator<Item = PublicKey> + '_;
41
42 #[must_use]
43 fn is_nonce_used(&self, account_id: &AccountIdRef, nonce: Nonce) -> bool;
44
45 #[must_use]
46 fn balance_of(&self, account_id: &AccountIdRef, token_id: &TokenId) -> u128;
47
48 fn is_account_locked(&self, account_id: &AccountIdRef) -> bool;
49
50 fn is_auth_by_predecessor_id_enabled(&self, account_id: &AccountIdRef) -> bool;
52
53 fn is_valid_salt(&self, salt: Salt) -> bool;
55
56 #[inline]
57 fn cached(self) -> CachedState<Self>
58 where
59 Self: Sized,
60 {
61 CachedState::new(self)
62 }
63}
64
65#[autoimpl(for<T: trait + ?Sized> &mut T, Box<T>)]
66pub trait State: StateView {
67 fn add_public_key(&mut self, account_id: AccountId, public_key: PublicKey) -> Result<()>;
68
69 fn remove_public_key(&mut self, account_id: AccountId, public_key: PublicKey) -> Result<()>;
70
71 fn commit_nonce(&mut self, account_id: AccountId, nonce: Nonce) -> Result<()>;
72
73 fn cleanup_nonce_by_prefix(
74 &mut self,
75 account_id: &AccountIdRef,
76 prefix: NoncePrefix,
77 ) -> Result<bool>;
78
79 fn internal_add_balance(
80 &mut self,
81 owner_id: AccountId,
82 tokens: impl IntoIterator<Item = (TokenId, u128)>,
83 ) -> Result<()>;
84
85 fn internal_sub_balance(
86 &mut self,
87 owner_id: &AccountIdRef,
88 tokens: impl IntoIterator<Item = (TokenId, u128)>,
89 ) -> Result<()>;
90
91 fn internal_apply_deltas(
92 &mut self,
93 owner_id: &AccountIdRef,
94 tokens: impl IntoIterator<Item = (TokenId, i128)>,
95 ) -> Result<()> {
96 for (token_id, delta) in tokens {
97 let tokens = [(token_id, delta.unsigned_abs())];
98 if delta.is_negative() {
99 self.internal_sub_balance(owner_id, tokens)?;
100 } else {
101 self.internal_add_balance(owner_id.to_owned(), tokens)?;
102 }
103 }
104 Ok(())
105 }
106
107 fn ft_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: FtWithdraw) -> Result<()>;
108
109 fn nft_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: NftWithdraw) -> Result<()>;
110
111 fn mt_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: MtWithdraw) -> Result<()>;
112
113 fn native_withdraw(&mut self, owner_id: &AccountIdRef, withdraw: NativeWithdraw) -> Result<()>;
114
115 fn notify_on_transfer(
116 &self,
117 sender_id: &AccountIdRef,
118 receiver_id: AccountId,
119 tokens: Amounts,
120 notification: NotifyOnTransfer,
121 );
122
123 fn storage_deposit(
124 &mut self,
125 owner_id: &AccountIdRef,
126 storage_deposit: StorageDeposit,
127 ) -> Result<()>;
128
129 fn set_auth_by_predecessor_id(&mut self, account_id: AccountId, enable: bool) -> Result<bool>;
132
133 fn auth_call(&mut self, signer_id: &AccountIdRef, auth_call: AuthCall) -> Result<()>;
134
135 fn mint(&mut self, owner_id: AccountId, tokens: Amounts, memo: Option<String>) -> Result<()>;
136
137 fn burn(
138 &mut self,
139 owner_id: &AccountIdRef,
140 tokens: Amounts,
141 memo: Option<String>,
142 ) -> Result<()>;
143
144 #[cfg(feature = "imt")]
145 fn imt_mint(
146 &mut self,
147 minter_id: &AccountIdRef,
148 receiver_id: AccountId,
149 tokens: ImtTokens,
150 memo: Option<String>,
151 notification: Option<NotifyOnTransfer>,
152 ) -> Result<()> {
153 if tokens.is_empty() {
154 return Err(DefuseError::InvalidIntent);
155 }
156
157 let tokens = tokens.into_generic_tokens(minter_id)?;
158 self.mint(receiver_id.clone(), tokens.clone(), memo)?;
159
160 if let Some(mut notification) = notification {
161 notification.min_gas = Some(
162 notification
163 .min_gas
164 .unwrap_or(MT_ON_TRANSFER_GAS_DEFAULT)
165 .max(MT_ON_TRANSFER_GAS_MIN),
166 );
167
168 self.notify_on_transfer(minter_id, receiver_id, tokens, notification);
169 }
170
171 Ok(())
172 }
173
174 #[cfg(feature = "imt")]
175 fn imt_burn(
176 &mut self,
177 owner_id: &AccountIdRef,
178 minter_id: &AccountIdRef,
179 tokens: ImtTokens,
180 memo: Option<String>,
181 ) -> Result<()> {
182 if tokens.is_empty() {
183 return Err(crate::DefuseError::InvalidIntent);
184 }
185
186 let tokens = tokens.into_generic_tokens(minter_id)?;
187
188 self.burn(owner_id, tokens, memo)
189 }
190}